/// <summary> /// Applies a local search strategy. /// </summary> /// <param name="problem"></param> /// <param name="route"></param> /// <returns></returns> public static void CalculateRePlaceOptHelper( IProblemWeights problem, IRoute route) { //bool improvement = true; //while (improvement) //{ //// reset improvement flag. //improvement = false; // try re-placement of one customer. int before = -1; //int after = -1; int found_customer = -1; // loop over all customers and try to place it better. HashSet <int> customers_to_place = new HashSet <int>(route); foreach (int customer_to_place in customers_to_place) { // find the best place. double current_cost = -1; double other_cost = double.MaxValue; int previous_before = -1; int previous = -1; foreach (int customer in route) { if (previous >= 0 && previous_before >= 0) { if (previous == customer_to_place) { current_cost = problem.Weight(previous_before, previous) + problem.Weight(previous, customer); } else if (previous_before != customer_to_place && customer != customer_to_place) { // calculate the cost. double cost = problem.Weight(previous_before, customer_to_place) + problem.Weight(customer_to_place, previous); if (cost < other_cost) { other_cost = cost; before = previous_before; //after = previous; found_customer = customer; } } } previous_before = previous; previous = customer; } // determine if the cost is better. if (current_cost > other_cost) { // the current cost is better. route.Remove(found_customer); //route.InsertAfterAndRemove(before, found_customer, after); route.InsertAfter(before, found_customer); break; } else { // current cost is not better. before = -1; //after = -1; found_customer = -1; } } //if (found_customer >= 0) //{ // a found customer. // improvement = true; //} //} }
/// <summary> /// Selects seed customers. /// </summary> /// <param name="weights"></param> /// <param name="k"></param> /// <returns></returns> public ICollection <int> SelectSeeds(IProblemWeights weights, int k) { List <int> seeds = new List <int>(); // randomly select k seeds. while (seeds.Count < k) { int new_seed = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(weights.Size); while (seeds.Contains(new_seed)) { new_seed = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(weights.Size); } seeds.Add(new_seed); } // find shortest distance. double minimal = double.MaxValue; int selected_idx = -1; for (int x = 0; x < k; x++) { for (int y = 0; y < x; y++) { double weight = weights.Weight(seeds[x], seeds[y]); if (weight < minimal) { selected_idx = x; minimal = weight; } } } // select any new seed and see if replacing the selected would yield better results. int max_tries = 2000; int tries = 0; while (tries < max_tries) { int seed = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(weights.Size); while (seeds.Contains(seed)) { seed = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(weights.Size); } // check the new minimal. double new_minimal = double.MaxValue; for (int x = 0; x < k; x++) { if (x != selected_idx) { double weight = weights.Weight(seeds[x], seed); if (weight < new_minimal) { new_minimal = weight; } } } // see if the new one has a higher minimal. if (new_minimal > minimal) { // ok there is an improvement! OsmSharp.Logging.Log.TraceEvent("SimpleSeeds", System.Diagnostics.TraceEventType.Information, "Seed new minimal: {0}->{1}", minimal, new_minimal); tries = 0; minimal = new_minimal; seeds[selected_idx] = seed; } tries++; // increase the number of tries. } OsmSharp.Logging.Log.TraceEvent("SimpleSeeds", System.Diagnostics.TraceEventType.Information, "Seed distance: {0}", minimal); return(seeds); }
/// <summary> /// Selects seed customers. /// </summary> /// <param name="weights"></param> /// <param name="k"></param> /// <returns></returns> public ICollection<int> SelectSeeds(IProblemWeights weights, int k) { List<int> seeds = new List<int>(); // randomly select k seeds. while (seeds.Count < k) { int new_seed = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(weights.Size); while (seeds.Contains(new_seed)) { new_seed = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(weights.Size); } seeds.Add(new_seed); } // find shortest distance. double minimal = double.MaxValue; int selected_idx = -1; for (int x = 0; x < k; x++) { for (int y = 0; y < x; y++) { double weight = weights.Weight(seeds[x], seeds[y]); if (weight < minimal) { selected_idx = x; minimal = weight; } } } // select any new seed and see if replacing the selected would yield better results. int max_tries = 2000; int tries = 0; while (tries < max_tries) { int seed = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(weights.Size); while (seeds.Contains(seed)) { seed = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(weights.Size); } // check the new minimal. double new_minimal = double.MaxValue; for (int x = 0; x < k; x++) { if (x != selected_idx) { double weight = weights.Weight(seeds[x], seed); if (weight < new_minimal) { new_minimal = weight; } } } // see if the new one has a higher minimal. if (new_minimal > minimal) { // ok there is an improvement! OsmSharp.Logging.Log.TraceEvent("SimpleSeeds", System.Diagnostics.TraceEventType.Information, "Seed new minimal: {0}->{1}", minimal, new_minimal); tries = 0; minimal = new_minimal; seeds[selected_idx] = seed; } tries++; // increase the number of tries. } OsmSharp.Logging.Log.TraceEvent("SimpleSeeds", System.Diagnostics.TraceEventType.Information, "Seed distance: {0}", minimal); return seeds; }
/// <summary> /// Returns the weight between two customers. /// </summary> /// <param name="from"></param> /// <param name="to"></param> /// <returns></returns> public double Weight(int from, int to) { return(_weights.Weight(from, to)); }
/// <summary> /// Applies a local search strategy. /// </summary> /// <param name="problem"></param> /// <param name="route"></param> /// <returns></returns> public static void CalculateRePlaceOptHelper( IProblemWeights problem, IRoute route) { //bool improvement = true; //while (improvement) //{ //// reset improvement flag. //improvement = false; // try re-placement of one customer. int before = -1; int after = -1; int found_customer = -1; // loop over all customers and try to place it better. HashSet<int> customers_to_place = new HashSet<int>(route); foreach (int customer_to_place in customers_to_place) { // find the best place. double current_cost = -1; double other_cost = double.MaxValue; int previous_before = -1; int previous = -1; foreach (int customer in route) { if (previous >= 0 && previous_before >= 0) { if (previous == customer_to_place) { current_cost = problem.Weight(previous_before, previous) + problem.Weight(previous, customer); } else if (previous_before != customer_to_place && customer != customer_to_place) { // calculate the cost. double cost = problem.Weight(previous_before, customer_to_place) + problem.Weight(customer_to_place, previous); if (cost < other_cost) { other_cost = cost; before = previous_before; after = previous; found_customer = customer; } } } previous_before = previous; previous = customer; } // determine if the cost is better. if (current_cost > other_cost) { // the current cost is better. route.Remove(found_customer); //route.InsertAfterAndRemove(before, found_customer, after); route.InsertAfter(before, found_customer); break; } else { // current cost is not better. before = -1; after = -1; found_customer = -1; } } //if (found_customer >= 0) //{ // a found customer. // improvement = true; //} //} }
/// <summary> /// Searches for the best place to insert the given two customers abstracting the distance between them. /// </summary> /// <param name="problem"></param> /// <param name="route"></param> /// <param name="from"></param> /// <param name="to"></param> /// <returns></returns> public static CheapestInsertionResult CalculateBestPlacement( IProblemWeights problem, IRoute route, int from, int to) { // initialize the best placement result. CheapestInsertionResult result = new CheapestInsertionResult(); result.Customer = -1; // this property is useless here! result.CustomerAfter = -1; result.CustomerBefore = -1; result.Increase = double.MaxValue; if (!route.IsEmpty) { double new_weight = double.MaxValue; double old_weight = 0; int previous = -1; int first = -1; foreach (int current in route) { if (previous >= 0) { // only if the previous is known. // calculate the new weights. new_weight = problem.Weight(previous, from) + (problem.Weight(to, current)); // calculate the old weights. old_weight = problem.Weight(previous, current); // calculate the difference. double difference = new_weight - old_weight; if (result.Increase > difference) { result.CustomerAfter = current; result.CustomerBefore = previous; result.Increase = difference; } } else { // store the first city for later. first = current; } // go to the next loop. previous = current; } // test last-to-first if the route is a round. if (route.IsRound) { // calculate the new weights. new_weight = problem.Weight(previous, from) + (problem.Weight(to, first)); // calculate the old weights. old_weight = problem.Weight(previous, first); // calculate the difference. double difference = new_weight - old_weight; if (result.Increase > difference) { result.CustomerBefore = previous; result.CustomerAfter = first; result.Increase = difference; } } } else { // route needs to be initialized. throw new ArgumentException("Route needs to be initialized with at least one customer!"); } // return result. return(result); }
/// <summary> /// Searches for the best place to insert the given two customers abstracting the distance between them. /// </summary> /// <param name="problem"></param> /// <param name="route"></param> /// <param name="from"></param> /// <param name="to"></param> /// <returns></returns> public static CheapestInsertionResult CalculateBestPlacement( IProblemWeights problem, IRoute route, int from, int to) { // initialize the best placement result. CheapestInsertionResult result = new CheapestInsertionResult(); result.Customer = -1; // this property is useless here! result.CustomerAfter = -1; result.CustomerBefore = -1; result.Increase = double.MaxValue; if (!route.IsEmpty) { double new_weight = double.MaxValue; double old_weight = 0; int previous = -1; int first = -1; foreach (int current in route) { if (previous >= 0) { // only if the previous is known. // calculate the new weights. new_weight = problem.Weight(previous, from) + (problem.Weight(to, current)); // calculate the old weights. old_weight = problem.Weight(previous, current); // calculate the difference. double difference = new_weight - old_weight; if (result.Increase > difference) { result.CustomerAfter = current; result.CustomerBefore = previous; result.Increase = difference; } } else { // store the first city for later. first = current; } // go to the next loop. previous = current; } // test last-to-first if the route is a round. if (route.IsRound) { // calculate the new weights. new_weight = problem.Weight(previous, from) + (problem.Weight(to, first)); // calculate the old weights. old_weight = problem.Weight(previous, first); // calculate the difference. double difference = new_weight - old_weight; if (result.Increase > difference) { result.CustomerBefore = previous; result.CustomerAfter = first; result.Increase = difference; } } } else { // route needs to be initialized. throw new ArgumentException("Route needs to be initialized with at least one customer!"); } // return result. return result; }