/// <summary> /// Improves an existing solution. /// </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) { if (!route.IsValid()) { throw new Exception(); } _dont_look_bits = new bool[problem.Size]; double[][] weights = problem.WeightMatrix; // loop over all customers. bool any_improvement = false; bool improvement = true; difference = -1; while (improvement) { improvement = false; foreach (int v_1 in route) { if (!this.Check(problem, v_1)) { if (this.Try3OptMoves(problem, weights, route, v_1)) { any_improvement = true; improvement = true; break; } this.Set(problem, v_1, true); } } } return(any_improvement); }
/// <summary> /// Returns true if the route is valid. /// </summary> /// <returns></returns> public bool IsValid() { if (_route == null) { return(true); } return(_route.IsValid() && !_route.Contains(0)); }
/// <summary> /// Apply some improvements within one route. /// </summary> /// <param name="problem"></param> /// <param name="route"></param> /// <param name="currentWeight"></param> private double ImproveIntraRoute(OsmSharp.Math.VRP.Core.IProblemWeights problem, IRoute route, double currentWeight) { bool improvement = true; double newWeight = currentWeight; while (improvement) { // keep trying while there are still improvements. improvement = false; // loop over all improvement operations. foreach (IImprovement improvementOperation in _intraImprovements) { // try the current improvement operations. double difference; if (improvementOperation.Improve(problem, route, out difference)) { // there was an improvement. OsmSharp.Logging.Log.TraceEvent("OsmSharp.Routing.VRP.WithDepot.MaxTime.VNS.GuidedVNS", TraceEventType.Information, "Intra-improvement found {0} {1}->{2}", improvementOperation.Name, newWeight, newWeight + difference); // check if the route is valid. if (!route.IsValid()) { throw new Exception(); } // update the weight. newWeight = newWeight + difference; improvement = true; break; } } } return(newWeight); }
/// <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> /// Apply some improvements between the given routes and returns the resulting weight. /// </summary> /// <param name="problem"></param> /// <param name="solution"></param> /// <param name="route1Idx"></param> /// <param name="route2Idx"></param> /// <param name="max"></param> /// <returns></returns> private bool ImproveInterRoute(MaxTimeProblem problem, MaxTimeSolution solution, int route1Idx, int route2Idx, double max) { // get the routes. IRoute route1 = solution.Route(route1Idx); IRoute route2 = solution.Route(route2Idx); int countBefore = route1.Count + route2.Count; // loop over all improvement operations. bool globalImprovement = false; foreach (IInterImprovement improvementOperation in _inter_improvements) { // try the current improvement operations. bool improvement = true; while (improvement) { // keep looping when there is improvement. improvement = false; double totalBefore = problem.Time(solution.Route(route1Idx)) + problem.Time(solution.Route(route2Idx)); if (improvementOperation.Improve(problem, solution, route1Idx, route2Idx, max)) { // there was an improvement. improvement = true; globalImprovement = true; // check if the route is valid. if (!route1.IsValid()) { throw new Exception(); } if (!route2.IsValid()) { throw new Exception(); } int countAfter = route1.Count + route2.Count; if (countBefore != countAfter) { throw new Exception(); } double totalAfter = problem.Time(solution.Route(route1Idx)) + problem.Time(solution.Route(route2Idx)); if (totalAfter >= totalBefore) { throw new Exception("this is not an improvement!"); } OsmSharp.Logging.Log.TraceEvent("OsmSharp.Routing.VRP.NoDepot.MaxTime.VNS.GuidedVNS", TraceEventType.Information, "Inter-improvement found {0}<->{1}: {2} ({3}->{4})", route1Idx, route2Idx, improvementOperation.Name, totalBefore, totalAfter); // recalculate weights. solution[route1Idx] = problem.Time(solution.Route(route1Idx)); solution[route2Idx] = problem.Time(solution.Route(route2Idx)); //break; } else if (!improvementOperation.IsSymmetric && improvementOperation.Improve(problem, solution, route2Idx, route1Idx, max)) { // also do the improvement the other way around when not symmetric. improvement = true; globalImprovement = true; // check if the route is valid. if (!route1.IsValid()) { throw new Exception(); } if (!route2.IsValid()) { throw new Exception(); } int countAfter = route1.Count + route2.Count; if (countBefore != countAfter) { throw new Exception(); } double totalAfter = problem.Time(solution.Route(route1Idx)) + problem.Time(solution.Route(route2Idx)); if (totalAfter >= totalBefore) { throw new Exception("this is not an improvement!"); } OsmSharp.Logging.Log.TraceEvent("OsmSharp.Routing.VRP.NoDepot.MaxTime.VNS.GuidedVNS", TraceEventType.Information, "Inter-improvement found {0}<->{1}: {2} ({3}->{4})", route2Idx, route1Idx, improvementOperation.Name, totalBefore, totalAfter); // recalculate weights. solution[route1Idx] = problem.Time(solution.Route(route1Idx)); solution[route2Idx] = problem.Time(solution.Route(route2Idx)); //break; } } } return(globalImprovement); }
/// <summary> /// Apply some improvements within one route. /// </summary> /// <param name="problem"></param> /// <param name="route"></param> /// <param name="currentWeight"></param> private double ImproveIntraRoute(IProblemWeights problem, IRoute route, double currentWeight) { bool improvement = true; double newWeight = currentWeight; while (improvement) { // keep trying while there are still improvements. improvement = false; // loop over all improvement operations. foreach (IImprovement improvementOperation in _intra_improvements) { // try the current improvement operations. double difference; if (improvementOperation.Improve(problem, route, out difference)) { // there was an improvement. OsmSharp.Logging.Log.TraceEvent("OsmSharp.Routing.VRP.NoDepot.MaxTime.VNS.GuidedVNS", TraceEventType.Information, "Intra-improvement found {0} {1}->{2}", improvementOperation.Name, newWeight, newWeight + difference); // check if the route is valid. if (!route.IsValid()) { throw new Exception(); } // update the weight. newWeight = newWeight + difference; improvement = true; break; } } } return newWeight; }
/// <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> /// Apply some improvements within one route. /// </summary> /// <param name="problem"></param> /// <param name="route"></param> /// <param name="current_weight"></param> private double ImproveIntraRoute(IProblemWeights problem, IRoute route, double current_weight) { bool improvement = true; double new_weight = current_weight; while (improvement) { // keep trying while there are still improvements. improvement = false; // loop over all improvement operations. foreach (IImprovement improvement_operation in _intra_improvements) { // try the current improvement operations. double difference; if (improvement_operation.Improve(problem, route, out difference)) { // there was an improvement. OsmSharp.Tools.Output.OutputStreamHost.WriteLine("Intra-improvement found {0} {1}->{2}", improvement_operation.Name, new_weight, new_weight + difference); // check if the route is valid. if (!route.IsValid()) { throw new Exception(); } // update the weight. new_weight = new_weight + difference; improvement = true; break; } } } return new_weight; }
/// <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); }
/// <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> /// Improves an existing solution. /// </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) { if (!route.IsValid()) { throw new Exception(); } _dont_look_bits = new bool[problem.Size]; double[][] weights = problem.WeightMatrix; // loop over all customers. bool any_improvement = false; bool improvement = true; difference = -1; while (improvement) { improvement = false; foreach (int v_1 in route) { if (!this.Check(problem, v_1)) { if (this.Try3OptMoves(problem, weights, route, v_1)) { any_improvement = true; improvement = true; break; } this.Set(problem, v_1, true); } } } return any_improvement; }