/// <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="weight_1_2"></param> /// <param name="v_3"></param> /// <returns></returns> public bool Try3OptMoves(IProblemWeights problem, double[][] weights, IRoute route, int v1, int v_2, double weight_1_2, int v_3) { // get v_4. int v_4 = route.GetNeigbours(v_3)[0]; double weight_1_2_plus_3_4 = weight_1_2 + weights[v_3][v_4]; double weight_1_4 = weights[v1][v_4]; double[] weights_3 = weights[v_3]; return(this.Try3OptMoves(problem, weights, route, v1, v_2, v_3, weights_3, v_4, weight_1_2_plus_3_4, weight_1_4)); }
/// <summary> /// Do get neighbour tests. /// </summary> protected void DoTestGetNeighbours() { int count = 10; IRoute route = this.BuildRoute(true); if (route != null) { // this part needs testing. for (int customer = 0; customer < count; customer++) { route.InsertAfter(customer - 1, customer); //route.InsertAfterAndRemove(customer - 1, customer, -1); } } int[] neighbours; for (int customer = 0; customer < count - 1; customer++) { neighbours = route.GetNeigbours(customer); Assert.IsTrue(neighbours[0] == customer + 1); } neighbours = route.GetNeigbours(count - 1); Assert.IsTrue(neighbours[0] == 0); }
/// <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> /// Returns the neighbours of the given customer. /// </summary> /// <param name="customer"></param> /// <returns></returns> public int[] GetNeigbours(int customer) { //int[] neighbour; //if (customer == 0) //{ // neighbour = new int[1]; // neighbour[0] = _route.First; //} //else if (_route.Last == customer) //{ // neighbour = new int[1]; // neighbour[0] = 0; //} return(_route.GetNeigbours(customer)); }
/// <summary> /// Returns the customer after the given customer. /// </summary> /// <param name="customer"></param> /// <returns></returns> public int Next(int customer) { int next = _next_array[customer]; if (next < 0) { for (int idx = 0; idx < this.Count; idx++) { IRoute route = this.Route(idx); if (route.Contains(customer) && route.GetNeigbours(customer)[0] == route.First) { return(route.First); } } } return(next); }
/// <summary> /// Tries all 3Opt Moves for the neighbourhood of v_1. /// </summary> /// <param name="problem"></param> /// <param name="weights"></param> /// <param name="route"></param> /// <param name="v1"></param> /// <returns></returns> public bool Try3OptMoves(IProblemWeights problem, double[][] weights, IRoute route, int v1) { // get v_2. int v_2 = route.GetNeigbours(v1)[0]; if (v_2 < 0) { return(false); } IEnumerable <int> between_v_2_v_1 = route.Between(v_2, v1); double weight_1_2 = weights[v1][v_2]; int v_3 = -1; NearestNeighbours10 neighbours = null; if (_nearest_neighbours) { neighbours = problem.Get10NearestNeighbours(v1); } foreach (int v_4 in between_v_2_v_1) { if (v_3 >= 0 && v_3 != v1) { //if (!_nearest_neighbours || // neighbours.Max <= weight_1_4) if (!_nearest_neighbours || neighbours.Contains(v_4)) { double weight_1_4 = weights[v1][v_4]; double weight_1_2_plus_3_4 = weight_1_2 + weights[v_3][v_4]; double[] weights_3 = weights[v_3]; if (this.Try3OptMoves(problem, weights, route, v1, v_2, v_3, weights_3, v_4, weight_1_2_plus_3_4, weight_1_4)) { return(true); } } } v_3 = v_4; } return(false); }
/// <summary> /// Applies inter-improvements by exchanging customers. /// </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) { 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)); double route1_size = solution[route1_idx]; double route2_size = solution[route2_idx]; // this heuristic removes a customer1 from route1 and a customer2 from route2 and inserts the customers again // but swappes them; customer1 in route2 and customer2 in route1. int previous_customer1 = -1; //if (route1.IsRound) //{ // previous_customer1= route1.Last; // set the previous customer. //} foreach (int customer1 in route1) { // loop over all customers in route1. if (previous_customer1 >= 0) { // the previous customer is set. int next_customer1 = route1.GetNeigbours(customer1)[0]; if (next_customer1 < 0) { continue; } int previous_customer2 = -1; //if (route2.IsRound) //{ // previous_customer2 = route2.Last; // set the previous customer. //} foreach (int customer2 in route2) { // loop over all customers in route2. int next_customer2 = route2.GetNeigbours(customer2)[0]; if (previous_customer2 >= 0 && next_customer2 >= 0) { // the previous customer is set. float weight1 = (float)problem.WeightMatrix[previous_customer1][customer1] + (float)problem.WeightMatrix[customer1][next_customer1]; float weight2 = (float)problem.WeightMatrix[previous_customer2][customer2] + (float)problem.WeightMatrix[customer2][next_customer2]; float weight1_after = (float)problem.WeightMatrix[previous_customer1][customer2] + (float)problem.WeightMatrix[customer2][next_customer1]; float weight2_after = (float)problem.WeightMatrix[previous_customer2][customer1] + (float)problem.WeightMatrix[customer1][next_customer2]; double difference = (weight1_after + weight2_after) - (weight1 + weight2); if (difference < -0.01) { // the old weights are bigger! // check if the new routes are bigger than max. if (route1_size + (weight1_after - weight1) <= max && route2_size + (weight2_after - weight1) <= max) { // the exchange can happen, both routes stay within bound! // exchange customer. int count_before = route1.Count + route2.Count; //route1.Remove(customer1); //route2.Remove(customer2); if (previous_customer1 == next_customer2) { throw new Exception(); } //route1.InsertAfter(previous_customer1, customer2); //route2.InsertAfter(previous_customer2, customer1); route1.ReplaceEdgeFrom(previous_customer1, customer2); route1.ReplaceEdgeFrom(customer2, next_customer1); route2.ReplaceEdgeFrom(previous_customer2, customer1); route2.ReplaceEdgeFrom(customer1, next_customer2); int count_after = route1.Count + route2.Count; if (count_before != count_after) { 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); } } } previous_customer2 = customer2; // set the previous customer. } } previous_customer1 = customer1; // set the previous customer. } return(false); }
internal override MaxTimeSolution Solve(MaxTimeProblem problem) { MaxTimeCalculator calculator = new MaxTimeCalculator( problem); // generate a ATSP solution. IRoute tsp_solution = _tsp_solution; if (tsp_solution == null) { tsp_solution = _tsp_solver.Solve(new TSPProblem(problem)); } // generate subtours from this solution. MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true); // select a random start point. int start = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(problem.Size); // start the first tour. int placed = 0; int previous = -1; // place the first customer. double weight = 0; double total_weight = 0; IRoute route = solution.Add(start); previous = start; while (placed < problem.Size) { // get the next customer from the tsp solution. int next = tsp_solution.GetNeigbours(previous)[0]; // get the weight to the current start. double weight_to_next = problem.WeightMatrix[previous][next]; double weight_to_start = problem.WeightMatrix[next][start]; total_weight = calculator.CalculateOneRouteIncrease( weight, weight_to_next + weight_to_start); weight = calculator.CalculateOneRouteIncrease( weight, weight_to_next); if (total_weight > problem.Max.Value) { // start a new route. route = solution.Add(next); weight = 0; } else { // just insert the next customer. route.InsertAfter(previous, next); //route.InsertAfterAndRemove(previous, next, -1); } // set the previous. previous = next; placed++; } if (!solution.IsValid()) { throw new Exception(); } StringBuilder builder = new StringBuilder(); builder.Append("["); total_weight = 0; for (int idx = 0; idx < solution.Count; idx++) { //IRoute route = routes.Route(idx); route = solution.Route(idx); weight = calculator.CalculateOneRoute(route); builder.Append(" "); builder.Append(weight); builder.Append(" "); total_weight = total_weight + weight; } builder.Append("]"); builder.Append(total_weight); builder.Append(": "); builder.Append(calculator.Calculate(solution)); Console.WriteLine(builder.ToString()); return(solution); }
/// <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="weight_1_2"></param> /// <param name="v_3"></param> /// <returns></returns> public bool Try3OptMoves(IProblemWeights problem, double[][] weights, IRoute route, int v1, int v_2, double weight_1_2, int v_3) { // get v_4. int v_4 = route.GetNeigbours(v_3)[0]; double weight_1_2_plus_3_4 = weight_1_2 + weights[v_3][v_4]; double weight_1_4 = weights[v1][v_4]; double[] weights_3 = weights[v_3]; return this.Try3OptMoves(problem, weights, route, v1, v_2, v_3, weights_3, v_4, weight_1_2_plus_3_4, weight_1_4); }
/// <summary> /// Tries all 3Opt Moves for the neighbourhood of v_1. /// </summary> /// <param name="problem"></param> /// <param name="weights"></param> /// <param name="route"></param> /// <param name="v1"></param> /// <returns></returns> public bool Try3OptMoves(IProblemWeights problem, double[][] weights, IRoute route, int v1) { // get v_2. int v_2 = route.GetNeigbours(v1)[0]; if (v_2 < 0) { return false; } IEnumerable<int> between_v_2_v_1 = route.Between(v_2, v1); double weight_1_2 = weights[v1][v_2]; int v_3 = -1; NearestNeighbours10 neighbours = null; if (_nearest_neighbours) { neighbours = problem.Get10NearestNeighbours(v1); } foreach (int v_4 in between_v_2_v_1) { if (v_3 >= 0 && v_3 != v1) { //if (!_nearest_neighbours || // neighbours.Max <= weight_1_4) if (!_nearest_neighbours || neighbours.Contains(v_4)) { double weight_1_4 = weights[v1][v_4]; double weight_1_2_plus_3_4 = weight_1_2 + weights[v_3][v_4]; double[] weights_3 = weights[v_3]; if (this.Try3OptMoves(problem, weights, route, v1, v_2, v_3, weights_3, v_4, weight_1_2_plus_3_4, weight_1_4)) { return true; } } } v_3 = v_4; } return false; }
/// <summary> /// Calculates a solution. /// </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); double max = problem.Max.Value; // keep placing customer until none are left. List <int> customers = new List <int>(problem.Customers); // create n routes. for (int customer = 0; customer < customers.Count; customer++) { solution.Add(customer); solution[solution.Count - 1] = calculator.CalculateOneRouteIncrease( 0, 0); } // creates a result. MergeResult result = new MergeResult(); result.Weight = double.MaxValue; // loop over all route pairs and merge the smallest merge. while (result != null) { // keep looping until there is no result anymore. result = new MergeResult(); result.Weight = double.MaxValue; for (int route1_idx = 1; route1_idx < solution.Count; route1_idx++) { // keep looping over all routes. for (int route2_idx = 0; route2_idx < solution.Count; route2_idx++) { // keep looping over all routes. if (route1_idx == route2_idx) { // only consider different routes. break; } // calculate the merge result. MergeResult current_result = this.TryMerge(problem, solution, route1_idx, route2_idx, problem.Max.Value); // evaluate the current result. if (current_result != null && current_result.Weight < result.Weight) { // current result is best. result = current_result; } } } // evaluate the result. if (result.Weight < double.MaxValue) { // there is a result; apply it! IRoute source = solution.Route(result.RouteSourceId); IRoute target = solution.Route(result.RouteTargetId); //string source_string = source.ToString(); //string target_string = target.ToString(); if (target.Count > 1 && target.First == target.GetNeigbours(result.CustomerTargetSource)[0]) { //throw new Exception(); } // create an enumeration of all customers of source in the correct order. IEnumerable <int> source_between = new List <int>( source.Between(result.CustomerSourceSource, result.CustomerSourceTarget)); // insert after the complete source. int previous = result.CustomerTargetSource; int next = target.GetNeigbours(result.CustomerTargetSource)[0]; foreach (int source_customer in source_between) { // insert. target.ReplaceEdgeFrom(previous, source_customer); previous = source_customer; // update previous. } target.ReplaceEdgeFrom(previous, next); // remove the source route. solution.Remove(result.RouteSourceId); solution.RemoveWeight(result.RouteTargetId); // calculate the weight of the new route. solution[result.RouteTargetId] = solution[result.RouteTargetId] + result.Weight + solution[result.RouteSourceId]; if (!solution.IsValid()) { throw new Exception(); } } else { // set the result null. result = null; } } return(solution); }