예제 #1
0
        /// <summary>
        /// Considers one customer for relocation.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="route"></param>
        /// <param name="previous"></param>
        /// <param name="current"></param>
        /// <param name="next"></param>
        /// <param name="route_weight"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        private bool ConsiderCustomer(IProblemWeights problem, IRoute route, int previous, int current, int next, double route_weight, double max)
        {
            // calculate the removal gain of the customer.
            double removal_gain = problem.WeightMatrix[previous][current] + problem.WeightMatrix[current][next]
                                  - problem.WeightMatrix[previous][next];

            if (removal_gain > 0.0001)
            {
                // try and place the customer in the next route.
                CheapestInsertionResult result =
                    CheapestInsertionHelper.CalculateBestPlacement(problem, route, current);
                if (result.Increase < removal_gain - 0.001 && route_weight + result.Increase < max)
                { // there is a gain in relocating this customer.
                    int count_before = route.Count;
//                    string route_string = route.ToString();

                    // and the route is still within bounds!
                    route.ReplaceEdgeFrom(result.CustomerBefore, result.Customer);
                    route.ReplaceEdgeFrom(result.Customer, result.CustomerAfter);

                    int count_after = route.Count;
                    if (count_before + 1 != count_after)
                    {
                        throw new Exception();
                    }
                    return(true);
                }
            }
            return(false);
        }
예제 #2
0
        /// <summary>
        /// Generates individuals based on a random first customer for each route.
        /// </summary>
        /// <param name="solver"></param>
        /// <returns></returns>
        public Individual <MaxTimeSolution, MaxTimeProblem, Fitness> Generate(
            Solver <MaxTimeSolution, MaxTimeProblem, Fitness> solver)
        {
            MaxTimeProblem problem = solver.Problem;

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

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

            for (int customer = 0; customer < problem.Size; customer++)
            {
                customers.Add(customer);
            }
            //BestPlacementHelper helper = new BestPlacementHelper();

            // keep placing customer until none are left.
            while (customers.Count > 0)
            {
                // select a random customer.
                double weight       = 0;
                int    customer_idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(customers.Count);
                int    customer     = customers[customer_idx];
                customers.RemoveAt(customer_idx);

                // use best placement to generate a route.
                IRoute current_route = solution.Add(customer);
                //Console.WriteLine("Starting new route with {0}", customer);
                while (customers.Count > 0)
                {
                    // calculate the best placement.
                    int customer_to_place          = customers[OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(customers.Count)];
                    CheapestInsertionResult result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customer_to_place);

                    // calculate the new weight.
                    double potential_weight = result.Increase + weight + 20;
                    // cram as many customers into one route as possible.
                    if (potential_weight < problem.Max.Value)
                    { // ok we are done!
                        customers.Remove(result.Customer);
                        //current_route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter);
                        current_route.InsertAfter(result.CustomerBefore, result.Customer);
                        weight = potential_weight;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            return(new Individual <MaxTimeSolution, MaxTimeProblem, Fitness>(solution));
        }
예제 #3
0
        /// <summary>
        /// Solves the given problem.
        /// </summary>
        /// <returns></returns>
        public sealed override Tour Solve(STSProblem problem, STSPObjective objective, out STSPFitness fitness)
        {
            // generate random pool to select customers from.
            if (_randomPool == null || _randomPool.Size < problem.Weights.Length)
            {
                _randomPool = new RandomPool(problem.Weights.Length);
            }
            else
            {
                _randomPool.Reset();
            }

            // keep adding customers until no more space is left or no more customers available.
            var tour = problem.CreateEmptyTour();

            fitness = new STSPFitness()
            {
                Weight    = 0,
                Customers = 1
            };
            while (_randomPool.MoveNext())
            {
                var customer = _randomPool.Current;
                if (customer == problem.First ||
                    customer == problem.Last)
                {
                    continue;
                }

                Pair location;
                var  cost = CheapestInsertionHelper.CalculateCheapest(tour, problem.Weights, customer, out location);
                if (cost + fitness.Weight < problem.Max)
                {
                    tour.InsertAfter(location.From, customer);

                    fitness.Weight    = fitness.Weight + cost;
                    fitness.Customers = fitness.Customers + 1;
                }
            }

            // calculate fitness.
            fitness = objective.Calculate(problem, tour);
            return(tour);
        }
        /// <summary>
        /// Re-inserts a customer in the route.
        /// </summary>
        /// <param name="weights"></param>
        /// <param name="route"></param>
        /// <param name="customer"></param>
        /// <param name="difference"></param>
        /// <returns></returns>
        public static bool InsertOne(IProblemWeights weights, IRoute route, int customer,
                                     out double difference)
        {
            // calculate placement.
            CheapestInsertionResult result =
                CheapestInsertionHelper.CalculateBestPlacement(weights, route, customer);

            // place the customer.
            if (result.CustomerAfter >= 0 && result.CustomerBefore >= 0)
            {
                //route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter);
                route.InsertAfter(result.CustomerBefore, result.Customer);
                difference =
                    -(weights.WeightMatrix[result.CustomerBefore][result.CustomerAfter]) +
                    (weights.WeightMatrix[result.CustomerBefore][result.Customer]) +
                    (weights.WeightMatrix[result.Customer][result.CustomerAfter]);
                return(true);
            }
            difference = 0;
            return(false);
        }
예제 #5
0
        /// <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);
        }
예제 #6
0
        /// <summary>
        /// Executes a solver procedure.
        /// </summary>
        /// <param name="problem"></param>
        /// <returns></returns>
        internal override MaxTimeSolution Solve(MaxTimeProblem problem)
        {
            // create the solution.
            var solution = new MaxTimeSolution(problem.Size);

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

            customers.RemoveAt(0);

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

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

            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.
                int customer = this.SelectSeed(problem, problem.MaxTimeCalculator, solution, customers);
                customers.Remove(customer);

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

                while (customers.Count > 0)
                {
                    // calculate the best placement.
                    CheapestInsertionResult result;
                    if (_useSeedCost)
                    { // use the seed cost; the cost to the seed customer.
                        result = CheapestInsertionHelper.CalculateBestPlacement(problem, currentRoute, customers,
                                                                                customer, 0.7);

                        // 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, currentRoute, customers, costs);
                    }

                    // calculate the new weight.
                    solution[solution.Count - 1] = problem.Time(solution.Route(solution.Count - 1));
                    double potentialWeight = problem.MaxTimeCalculator.CalculateOneRouteIncrease(solution[solution.Count - 1],
                                                                                                 result.Increase);
                    // cram as many customers into one route as possible.
                    if (potentialWeight < max)
                    {
                        // insert the customer, it is
                        customers.Remove(result.Customer);
                        currentRoute.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] = potentialWeight;

                        // improve if needed.
                        if (((problem.Size - customers.Count) % _k) == 0)
                        { // an improvement is decided.
                            // apply the inter-route improvements.
                            var copy = (solution.Clone() as MaxTimeSolution);

                            int countBefore = solution.Route(solution.Count - 1).Count;

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

                            // also to the inter-improvements.
                            currentRoute = 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 routeIdx = solution.Count - 1; routeIdx >= 0; routeIdx--)
            {
                if (solution.Route(routeIdx).IsEmpty)
                {
                    solution.Remove(routeIdx);
                }
            }

            return(solution);
        }
예제 #7
0
        /// <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);
        }
예제 #8
0
        /// <summary>
        /// Does the mutation.
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="mutating"></param>
        /// <returns></returns>
        public Individual <List <Genome>, Problem, Fitness> Mutate(
            Solver <List <Genome>, Problem, Fitness> solver,
            Individual <List <Genome>, Problem, Fitness> mutating)
        {
            // get the route information.
            Genome multi_route = mutating.Genomes[0];

            int[] size_new      = null;
            int[] customers_new = null;

            if (multi_route.Sizes.Length > 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.Sizes.Length);
                int target_route_idx = -1;
                do
                {
                    target_route_idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(multi_route.Sizes.Length);
                } 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;
                    List <int> part_of_orginal = new List <int>();
                    foreach (int customer in multi_route.Customers)
                    {
                        idx++;
                        if (idx >= first && idx <= last)
                        {
                            part_of_orginal.Add(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]);

                        // create a new array and start copying.
                        customers_new = new int[multi_route.Customers.Length];
                        int new_idx = 0;
                        for (idx = 0; idx < multi_route.Customers.Length; idx++)
                        {
                            if (idx >= first && idx <= last)
                            {
                                // do nothing.
                            }
                            else
                            {
                                customers_new[new_idx] = multi_route.Customers[idx];
                                new_idx++;

                                if (multi_route.Customers[idx] == route_placement.CustomerBefore)
                                { // insert the entire between part here.
                                    for (int between_idx = 0; between_idx < part_of_orginal.Count; between_idx++)
                                    {
                                        customers_new[new_idx] = part_of_orginal[between_idx];
                                        new_idx++;
                                    }
                                }
                            }
                        }

                        // adjust sizes array.
                        size_new = new int[multi_route.Sizes.Length];
                        for (idx = 0; idx < multi_route.Sizes.Length; idx++)
                        {
                            if (idx == source_route_idx)
                            {
                                size_new[idx] = multi_route.Sizes[idx] - part_of_orginal.Count;
                            }
                            else if (idx == target_route_idx)
                            {
                                size_new[idx] = multi_route.Sizes[idx] + part_of_orginal.Count;
                            }
                            else
                            {
                                size_new[idx] = multi_route.Sizes[idx];
                            }
                        }
                    }
                }
            }

            if (size_new == null || customers_new == null)
            {
                size_new      = multi_route.Sizes.Clone() as int[];
                customers_new = multi_route.Customers.Clone() as int[];
            }

            // remove all zero's.
            List <int> sizes = new List <int>(size_new);

            while (sizes.Remove(0))
            {
            }
            size_new = sizes.ToArray <int>();

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

            genome.Sizes     = size_new;
            genome.Customers = customers_new;

            if (!genome.IsValid())
            {
                throw new Exception();
            }
            genomes.Add(genome);
            Individual <List <Genome>, Problem, Fitness> individual = new Individual <List <Genome>, Problem, Fitness>(genomes);

            //individual.Initialize();
            return(individual);
        }
예제 #9
0
        /// <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 = 10;

            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);
        }
예제 #10
0
        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);
        }
        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>
        /// Applies this operator.
        /// </summary>
        public bool Apply(STSProblem problem, STSPObjective objective, Tour solution, out STSPFitness delta)
        {
            var before  = objective.Calculate(problem, solution);
            var weights = problem.Weights;

            delta = objective.Zero;

            var i        = _n;
            var toInsert = new List <int>();

            if (!_insertNew)
            { // select existing customers, to reinsert.
                while (solution.Count > 1 && i > 0)
                {
                    i--;
                    var index   = RandomGeneratorExtensions.GetRandom().Generate(solution.Count);
                    var current = solution.GetCustomerAt(index);
                    if (current != Constants.NOT_SET)
                    {
                        if (current != solution.First &&
                            current != solution.Last &&
                            solution.Remove(current))
                        {
                            toInsert.Add(current);
                        }
                    }
                }
            }
            else if (solution.Count < problem.Weights.Length)
            { // select random new customer to insert.
                while (solution.Count > 1 && i > 0)
                {
                    i--;
                    var current = RandomGeneratorExtensions.GetRandom().Generate(problem.Weights.Length);
                    if (!solution.Contains(current))
                    {
                        if (current != solution.First &&
                            current != solution.Last &&
                            solution.Remove(current))
                        {
                            toInsert.Add(current);
                        }
                    }
                }
            }

            var fitness = objective.Calculate(problem, solution);

            foreach (var current in toInsert)
            {
                // insert new.
                Pair position;
                var  cost = CheapestInsertionHelper.CalculateCheapest(solution, weights, current, out position);
                if (cost + fitness.Weight < problem.Max)
                {
                    solution.InsertAfter(position.From, current);
                    fitness.Weight    = fitness.Weight + cost;
                    fitness.Customers = fitness.Customers + 1;
                }
            }

            var after = objective.Calculate(problem, solution);

            delta = objective.Subtract(problem, after, before);
            return(objective.CompareTo(problem, before, after) > 0);
        }
예제 #13
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);
        }
예제 #14
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);
        }
예제 #15
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;
                        }
                    }
                    //else
                    //{// ok we are done!
                    //    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;

                    //    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);
        }
예제 #16
0
        /// <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>
        /// 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));
        }