/// <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>
        /// 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>
 /// Executes the RAI.
 /// </summary>
 /// <param name="problem"></param>
 /// <param name="initial_route"></param>
 /// <returns></returns>
 public static IRoute DoSolve(IProblem problem, IRoute initial_route)
 {
     return(RandomizedArbitraryInsertionSolver.DoSolve(null, problem, initial_route));
 }