/// <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);
        }
        /// <summary>
        /// Tries a relocation of the customers in route1 to route2.
        /// </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>
        private bool RelocateFromTo(MaxTimeProblem problem, MaxTimeSolution solution,
                                    int route1_idx, int route2_idx, double max)
        {
            int previous = -1;
            int current  = -1;

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

            double route2_weight = solution[route2_idx];

            foreach (int next in route1)
            {
                if (previous >= 0 && current >= 0)
                { // consider the next customer.
                    int count_before1 = route1.Count;
                    int count_before2 = route2.Count;

                    string route1_string = route1.ToString();
                    string route2_string = route2.ToString();

                    if (this.ConsiderCustomer(problem, route2, previous, current, next, route2_weight, max))
                    {
                        route1.ReplaceEdgeFrom(previous, next);

                        int count_after = route1.Count + route2.Count;
                        if ((count_before1 + count_before2) != count_after)
                        {
                            throw new Exception();
                        }
                        return(true);
                    }
                }

                previous = current;
                current  = next;
            }

            return(false);
        }
Exemple #3
0
 public override string ToString()
 {
     return("Routes " + routeA.ToString() + " and " + routeB.ToString() + " on connection between stations " + stations.StationAKey + " and " + stations.StationBKey + ".");
 }
        public Individual <MaxTimeSolution, MaxTimeProblem, Fitness> CrossOver(
            Solver <MaxTimeSolution, MaxTimeProblem, Fitness> solver,
            Individual <MaxTimeSolution, MaxTimeProblem, Fitness> parent1,
            Individual <MaxTimeSolution, MaxTimeProblem, Fitness> parent2)
        {
            MaxTimeCalculator calculator = new MaxTimeCalculator(solver.Problem);

            MaxTimeSolution route1 = parent1.Genomes;
            MaxTimeSolution route2 = parent2.Genomes;

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

            if (route2.Count < size)
            {
                size = route2.Count;
            }

            // 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 = this.ChooseNextFrom(selected_routes, route1, selected_first);

                    selected_first.Add(selected_route);
                    selected_routes.Add(route1.Route(selected_route));
                }
                else
                {
                    selected_route = this.ChooseNextFrom(selected_routes, route2, selected_second);

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

                first = !first;
            }

            // generate the new customer genome.
            MaxTimeSolution solution = new MaxTimeSolution(route1.Size, true);

            int previous = -1;

            foreach (IRoute route in selected_routes)
            {
                IRoute current_route = null;
                foreach (int customer in route)
                {
                    MaxTimeSolution copy            = (solution.Clone() as MaxTimeSolution);
                    string          solution_string = solution.ToString();
                    if (!solution.Contains(customer))
                    {
                        if (current_route == null)
                        { // add the route.
                            current_route = solution.Add(customer);

                            // safe the previous customer.
                            previous = customer;

                            if (!solution.IsValid())
                            {
                                throw new Exception();
                            }
                        }
                        else
                        { // add the customer.
                            string current_route_string = current_route.ToString();
                            //current_route.InsertAfterAndRemove(previous, customer, current_route.First);
                            current_route.InsertAfter(previous, customer);
                            //current_route.InsertAfter(customer, current_route.First);

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

                            // safe the previous customer.
                            previous = customer;
                        }
                    }
                }
            }

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

            this.FillRoutes(calculator, route1, solution, solver.Problem);

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

            return(new Individual <MaxTimeSolution, MaxTimeProblem, Fitness>(solution));
        }
 public override string ToString()
 {
     return("Routes " + routeA.ToString() + " and " + routeB.ToString() + " at station " + stationKey + ".");
 }
        public void TestDepotDynamicAsymmetricMultiRouteExchanges()
        {
            // create two routes.
            // 0->11->12->13->14->15->0
            // 0->21->22->23->24->25->0
            var    multiRoute = new MaxTimeSolution(0);
            IRoute route1     = multiRoute.Add();
            var    customers  = new List <int>(route1);

            Assert.AreEqual(1, customers.Count);
            Assert.AreEqual(0, customers[0]);
            route1.InsertAfter(0, 11);
            Assert.AreEqual("0->11", route1.ToString());
            route1.InsertAfter(11, 12);
            route1.InsertAfter(12, 13);
            route1.InsertAfter(13, 14);
            route1.InsertAfter(14, 15);
            IRoute route2 = multiRoute.Add();

            customers = new List <int>(route2);
            Assert.AreEqual(1, customers.Count);
            Assert.AreEqual(0, customers[0]);
            route2.InsertAfter(0, 21);
            Assert.AreEqual("0->21", route2.ToString());
            route2.InsertAfter(21, 22);
            route2.InsertAfter(22, 23);
            route2.InsertAfter(23, 24);
            route2.InsertAfter(24, 25);

            customers = new List <int>(route1);
            Assert.AreEqual(6, customers.Count);
            Assert.AreEqual(0, customers[0]);
            Assert.AreEqual(11, customers[1]);
            Assert.AreEqual(12, customers[2]);
            Assert.AreEqual(13, customers[3]);
            Assert.AreEqual(14, customers[4]);
            Assert.AreEqual(15, customers[5]);


            customers = new List <int>(route2);
            Assert.AreEqual(6, customers.Count);
            Assert.AreEqual(0, customers[0]);
            Assert.AreEqual(21, customers[1]);
            Assert.AreEqual(22, customers[2]);
            Assert.AreEqual(23, customers[3]);
            Assert.AreEqual(24, customers[4]);
            Assert.AreEqual(25, customers[5]);

            // replace the entire first route.
            route1.ReplaceEdgeFrom(0, 0);

            route2.ReplaceEdgeFrom(25, 11);
            route2.ReplaceEdgeFrom(11, 12);
            route2.ReplaceEdgeFrom(12, 13);
            route2.ReplaceEdgeFrom(13, 14);
            route2.ReplaceEdgeFrom(14, 15);

            Assert.IsTrue(multiRoute.IsValid());

            // create two routes.
            // 0->11->12->13->14->15->0
            // 0->21->22->23->24->25->0
            multiRoute = new MaxTimeSolution(0);
            route1     = multiRoute.Add();
            customers  = new List <int>(route1);
            Assert.AreEqual(1, customers.Count);
            Assert.AreEqual(0, customers[0]);
            route1.InsertAfter(0, 11);
            Assert.AreEqual("0->11", route1.ToString());
            route1.InsertAfter(11, 12);
            route1.InsertAfter(12, 13);
            route1.InsertAfter(13, 14);
            route1.InsertAfter(14, 15);
            route2    = multiRoute.Add();
            customers = new List <int>(route2);
            Assert.AreEqual(1, customers.Count);
            Assert.AreEqual(0, customers[0]);
            route2.InsertAfter(0, 21);
            Assert.AreEqual("0->21", route2.ToString());
            route2.InsertAfter(21, 22);
            route2.InsertAfter(22, 23);
            route2.InsertAfter(23, 24);
            route2.InsertAfter(24, 25);

            // exchange parts.
            var part1 = new List <int>(route1.Between(11, 13));
            var part2 = new List <int>(route2.Between(23, 25));

            route1.ReplaceEdgeFrom(0, 14);
            route2.ReplaceEdgeFrom(22, 0);

            int previous = 0;

            for (int idx = 0; idx < part2.Count; idx++)
            {
                route1.ReplaceEdgeFrom(previous, part2[idx]);
                previous = part2[idx];
            }
            route1.ReplaceEdgeFrom(previous, 14);

            previous = 22;
            for (int idx = 0; idx < part1.Count; idx++)
            {
                route2.ReplaceEdgeFrom(previous, part1[idx]);
                previous = part1[idx];
            }
            route2.ReplaceEdgeFrom(previous, 0);

            Assert.IsTrue(multiRoute.IsValid());

            customers = new List <int>(route1);
            Assert.AreEqual(6, customers.Count);
            Assert.AreEqual(0, customers[0]);
            Assert.AreEqual(23, customers[1]);
            Assert.AreEqual(24, customers[2]);
            Assert.AreEqual(25, customers[3]);
            Assert.AreEqual(14, customers[4]);
            Assert.AreEqual(15, customers[5]);

            customers = new List <int>(route2);
            Assert.AreEqual(6, customers.Count);
            Assert.AreEqual(0, customers[0]);
            Assert.AreEqual(21, customers[1]);
            Assert.AreEqual(22, customers[2]);
            Assert.AreEqual(11, customers[3]);
            Assert.AreEqual(12, customers[4]);
            Assert.AreEqual(13, customers[5]);

            // create two routes.
            // 0->11->12->13->14->15->0
            // 0->21->22->23->24->25->0
            multiRoute = new MaxTimeSolution(0);
            route1     = multiRoute.Add();
            customers  = new List <int>(route1);
            Assert.AreEqual(1, customers.Count);
            Assert.AreEqual(0, customers[0]);
            route1.InsertAfter(0, 11);
            Assert.AreEqual("0->11", route1.ToString());
            route1.InsertAfter(11, 12);
            route1.InsertAfter(12, 13);
            route1.InsertAfter(13, 14);
            route1.InsertAfter(14, 15);
            route2    = multiRoute.Add();
            customers = new List <int>(route2);
            Assert.AreEqual(1, customers.Count);
            Assert.AreEqual(0, customers[0]);
            route2.InsertAfter(0, 21);
            Assert.AreEqual("0->21", route2.ToString());
            route2.InsertAfter(21, 22);
            route2.InsertAfter(22, 23);
            route2.InsertAfter(23, 24);
            route2.InsertAfter(24, 25);

            route1.ReplaceEdgeFrom(12, 15);
            route1.ReplaceEdgeFrom(14, 11);
            route1.ReplaceEdgeFrom(0, 13);

            customers = new List <int>(route1);
            Assert.AreEqual(6, customers.Count);
            Assert.AreEqual(0, customers[0]);
            Assert.AreEqual(13, customers[1]);
            Assert.AreEqual(14, customers[2]);
            Assert.AreEqual(11, customers[3]);
            Assert.AreEqual(12, customers[4]);
            Assert.AreEqual(15, customers[5]);

            route1.ToString();
        }
        /// <summary>
        /// Tries to improve the existing route using CI and return true if succesful.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="route"></param>
        /// <param name="difference"></param>
        /// <returns></returns>
        public bool Improve(IProblemWeights problem, IRoute route, out double difference)
        {
            bool improvement = false;

            difference = 0;
            if (route.Count > 3)
            {
                // loop over all customers and try cheapest insertion.
                for (int customer = 0; customer < problem.Size; customer++)
                {
                    string route_string = route.ToString();
                    //IRoute previous = route.Clone() as IRoute;
                    if (route.Contains(customer))
                    {
                        // remove customer and keep position.
                        int next = route.GetNeigbours(customer)[0];
                        route.Remove(customer);

                        // insert again.
                        ArbitraryInsertionSolver.InsertOne(problem, route, customer, out difference);

                        if (!route.IsValid())
                        {
                            throw new Exception();
                        }
                        if (route.GetNeigbours(customer)[0] != next
                            && difference < 0)
                        { // another customer was found as the best, improvement is succesful.
                            improvement = true;
                            break;
                        }
                    }
                }
            }
            return improvement;
        }
        /// <summary>
        /// Tries all 3Opt Moves for the neighbourhood of v_1 containing v_3.
        /// </summary>
        /// <param name="problem"></param>
        /// <param name="weights"></param>
        /// <param name="route"></param>
        /// <param name="v1"></param>
        /// <param name="v_2"></param>
        /// <param name="v_3"></param>
        /// <param name="weights_3"></param>
        /// <param name="v_4"></param>
        /// <param name="weight_1_2_plus_3_4"></param>
        /// <param name="weight_1_4"></param>
        /// <returns></returns>
        public bool Try3OptMoves(IProblemWeights problem, double[][] weights, IRoute route,
            int v1, int v_2, int v_3, double[] weights_3, int v_4, double weight_1_2_plus_3_4, double weight_1_4)
        {
            //IEnumerable<int> between_v_4_v_1 = route.Between(v_4, v_1);
            //foreach (int v_5 in between_v_4_v_1)
            //{
            //    if (v_5 != v_1)
            //    {
            //        if (this.Try3OptMove(problem, weights, route, v_1, v_2, v_3, weights_3, v_4, weight_1_2_plus_3_4, weight_1_4, v_5))
            //        {
            //            return true;
            //        }
            //    }
            //}
            //return false;

            IEnumerator<int> between_v_4_v_1_enumerator = route.Between(v_4, v1).GetEnumerator();
            if (between_v_4_v_1_enumerator.MoveNext())
            {
                int v_5 = between_v_4_v_1_enumerator.Current;
                if (v_5 != v1)
                {
                    while (between_v_4_v_1_enumerator.MoveNext())
                    {
                        int v_6 = between_v_4_v_1_enumerator.Current;
                        //Console.WriteLine(v_6);
                        //if (this.Try3OptMove(problem, weights,
                        //    route, v_1, v_2, v_3, weights_3, v_4,
                        //    weight_1_2_plus_3_4, weight_1_4, v_5, v_6))
                        //{
                        // calculate the total weight of the 'new' arcs.
                        double weight_new = weight_1_4 +
                            weights_3[v_6] +
                            weights[v_5][v_2];

                        // calculate the total weights.
                        double weight = weight_1_2_plus_3_4 + weights[v_5][v_6];

                        if (weight - weight_new > _epsilon)
                        { // actually do replace the vertices.
                            int count_before = route.Count;
                            string route_string = route.ToString();

                            route.ReplaceEdgeFrom(v1, v_4);
                            route.ReplaceEdgeFrom(v_3, v_6);
                            route.ReplaceEdgeFrom(v_5, v_2);

                            int count_after = route.Count;

                            if (count_before != count_after)
                            {
                                throw new Exception();
                            }
                            // set bits.
                            //this.Set(problem, v_1, false);
                            this.Set(problem, v_3, false);
                            this.Set(problem, v_5, false);

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

                            return true; // move succeeded.
                        }
                        //}
                        v_5 = v_6;
                    }
                }
            }
            return false;
        }
        /// <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;
        }