/// <summary> /// Test removing adding every customer at every position. /// </summary> public void DoTestAddRemoveComplete() { // create a new empty route. const int count = 10; for (int customerToRemove = 0; customerToRemove < count; customerToRemove++) { for (int customerToPlaceAfter = 0; customerToPlaceAfter < count; customerToPlaceAfter++) { if (customerToRemove != customerToPlaceAfter) { 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); } route.Remove(customerToRemove); route.InsertAfter(customerToPlaceAfter, customerToRemove); //route.InsertAfterAndRemove(customer_to_place_after, customer_to_remove, -1); Assert.IsTrue(route.Contains(customerToPlaceAfter, customerToRemove)); Assert.AreEqual(count, route.Count); var customersInRoute = new HashSet <int>(route); Assert.AreEqual(customersInRoute.Count, route.Count); } } } } }
/// <summary> /// Tests all enumerations of a route. /// </summary> protected void DoTestEnumerateBetween() { 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); } } for (int from = 0; from < count; from++) { for (int to = 0; to < count; to++) { IEnumerator <int> enumerator = route.Between(from, to).GetEnumerator(); for (int customer = from; customer - 1 != to; customer++) { if (customer == count) { customer = 0; } Assert.IsTrue(enumerator.MoveNext()); Assert.AreEqual(customer, enumerator.Current); } } } }
/// <summary> /// Tests enumeration all edges. /// </summary> protected void DoTestEnumeratePairs() { // create a new empty route. IRoute route = this.BuildRoute(0, true); // do the enumerable. List <Edge> edges = new List <Edge>(route.Edges()); Assert.AreEqual(0, edges.Count); if (route != null) { // this part needs testing! Assert.AreEqual(1, route.Count); Assert.AreEqual(false, route.IsEmpty); Assert.AreEqual(true, route.IsRound); for (int customer = 1; customer < 100; customer++) { route.InsertAfter(customer - 1, customer); //route.InsertAfterAndRemove(customer - 1, customer, -1); edges = new List <Edge>(route.Edges()); Assert.AreEqual(customer + 1, edges.Count); for (int edge_from = 0; edge_from < customer; edge_from++) { Assert.AreEqual(edges[edge_from].From, edge_from); Assert.AreEqual(edges[edge_from].To, edge_from + 1); } Assert.AreEqual(edges[edges.Count - 1].From, edges.Count - 1); Assert.AreEqual(edges[edges.Count - 1].To, 0); } } }
/// <summary> /// Tests if the route containts functions work correctly. /// </summary> public void DoTestContains() { // create a new empty route. const int count = 100; IRoute route = this.BuildRoute(true); if (route != null) { // this part needs testing. Assert.AreEqual(0, route.Count); Assert.AreEqual(true, route.IsEmpty); Assert.AreEqual(true, route.IsRound); for (int customer = 0; customer < count; customer++) { route.InsertAfter(customer - 1, customer); //route.InsertAfterAndRemove(customer - 1, customer, -1); Assert.AreEqual(customer + 1, route.Count); Assert.AreEqual(false, route.IsEmpty); Assert.AreEqual(true, route.IsRound); Assert.AreEqual(0, route.First); Assert.AreEqual(0, route.Last); } for (int customer = 0; customer < count - 1; customer++) { Assert.IsTrue(route.Contains(customer)); Assert.IsTrue(route.Contains(customer, customer + 1)); } Assert.IsTrue(route.Contains(count - 1)); Assert.IsTrue(route.Contains(count - 1, 0)); } }
/// <summary> /// Some tests on an IRoute. /// </summary> public void DoTestAdd() { // create a new empty route. IRoute route = this.BuildRoute(0, true); if (route != null) { // this part needs testing! Assert.AreEqual(1, route.Count); Assert.AreEqual(false, route.IsEmpty); Assert.AreEqual(true, route.IsRound); for (int customer = 1; customer < 100; customer++) { route.InsertAfter(customer - 1, customer); //route.InsertAfterAndRemove(customer - 1, customer, -1); Assert.AreEqual(customer + 1, route.Count); Assert.AreEqual(false, route.IsEmpty); Assert.AreEqual(true, route.IsRound); Assert.AreEqual(0, route.First); Assert.AreEqual(0, route.Last); } } // create a new empty route. route = this.BuildRoute(true); if (route != null) { // this part needs testing. Assert.AreEqual(0, route.Count); Assert.AreEqual(true, route.IsEmpty); Assert.AreEqual(true, route.IsRound); for (int customer = 0; customer < 100; customer++) { route.InsertAfter(customer - 1, customer); //route.InsertAfterAndRemove(customer - 1, customer, -1); Assert.AreEqual(customer + 1, route.Count); Assert.AreEqual(false, route.IsEmpty); Assert.AreEqual(true, route.IsRound); Assert.AreEqual(0, route.First); Assert.AreEqual(0, route.Last); } } }
/// <summary> /// Removes the edge from->unknown and replaces it with the edge from->to->unknown. /// 0->1:InsertAfter(0, 2):0->2-1 /// </summary> /// <param name="from"></param> /// <param name="to"></param> public void InsertAfter(int from, int to) { if (from == 0) { _route.InsertFirst(to); } else { _route.InsertAfter(from, to); } }
/// <summary> /// Generates individuals based on a random first customer for each route. /// </summary> /// <param name="solver"></param> /// <returns></returns> public Individual <MaxTimeSolution, MaxTimeProblem, Fitness> Generate( Solver <MaxTimeSolution, MaxTimeProblem, Fitness> solver) { MaxTimeProblem problem = solver.Problem; MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true); // create the problem for the genetic algorithm. List <int> customers = new List <int>(); for (int customer = 0; customer < problem.Size; customer++) { customers.Add(customer); } //BestPlacementHelper helper = new BestPlacementHelper(); // keep placing customer until none are left. while (customers.Count > 0) { // select a random customer. double weight = 0; int customer_idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(customers.Count); int customer = customers[customer_idx]; customers.RemoveAt(customer_idx); // use best placement to generate a route. IRoute current_route = solution.Add(customer); //Console.WriteLine("Starting new route with {0}", customer); while (customers.Count > 0) { // calculate the best placement. int customer_to_place = customers[OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(customers.Count)]; CheapestInsertionResult result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customer_to_place); // calculate the new weight. double potential_weight = result.Increase + weight + 20; // cram as many customers into one route as possible. if (potential_weight < problem.Max.Value) { // ok we are done! customers.Remove(result.Customer); //current_route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter); current_route.InsertAfter(result.CustomerBefore, result.Customer); weight = potential_weight; } else { break; } } } return(new Individual <MaxTimeSolution, MaxTimeProblem, Fitness>(solution)); }
/// <summary> /// Tests adding customers. /// </summary> public void DoTestRemove() { IMultiRoute multiRoute = this.BuildRoute(true); Assert.AreEqual(0, multiRoute.Count); int count = 10; int routes = 3; // test with initializing the routes empty. var customersPerRoute = new List <List <int> >(); Assert.AreEqual(0, multiRoute.Count); for (int routeIdx = 0; routeIdx < routes; routeIdx++) { customersPerRoute.Add(new List <int>()); int customerStart = (routeIdx * count); IRoute route = multiRoute.Add(); for (int customer = customerStart; customer < customerStart + count; customer++) { customersPerRoute[routeIdx].Add(customer); route.InsertAfter(customer - 1, customer); //route.InsertAfterAndRemove(customer - 1, customer, -1); } } // remove all the customers. while (customersPerRoute.Count > 0) { int routeIdx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(customersPerRoute.Count); int customerIdx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(customersPerRoute[routeIdx].Count); int customer = customersPerRoute[routeIdx][customerIdx]; customersPerRoute[routeIdx].RemoveAt(customerIdx); IRoute route = multiRoute.Route(routeIdx); route.Remove(customer); Assert.AreEqual(customersPerRoute[routeIdx].Count, route.Count); Assert.AreEqual(customersPerRoute[routeIdx].Count == 0, route.IsEmpty); Assert.AreEqual(true, route.IsRound); Assert.AreEqual(route.First, route.Last); if (customersPerRoute[routeIdx].Count == 0) { customersPerRoute.RemoveAt(routeIdx); multiRoute.Remove(routeIdx); } } }
/// <summary> /// Re-inserts a customer in the route. /// </summary> /// <param name="weights"></param> /// <param name="route"></param> /// <param name="customer"></param> /// <param name="difference"></param> /// <returns></returns> public static bool InsertOne(IProblemWeights weights, IRoute route, int customer, out double difference) { // calculate placement. CheapestInsertionResult result = CheapestInsertionHelper.CalculateBestPlacement(weights, route, customer); // place the customer. if (result.CustomerAfter >= 0 && result.CustomerBefore >= 0) { //route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter); route.InsertAfter(result.CustomerBefore, result.Customer); difference = -(weights.WeightMatrix[result.CustomerBefore][result.CustomerAfter]) + (weights.WeightMatrix[result.CustomerBefore][result.Customer]) + (weights.WeightMatrix[result.Customer][result.CustomerAfter]); return(true); } difference = 0; return(false); }
/// <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); }
public MaxTimeSolution ChangeSizes(MaxTimeProblem problem, MaxTimeSolution solution, IEnumerable <int> sizes) { MaxTimeSolution changed_solution = new MaxTimeSolution( solution.Size, true); //int[] next_array = new int[solution.Size]; bool[] used = new bool[solution.Size]; //List<int> first = new List<int>(); foreach (int size in sizes) { int current = 0; while (used[current]) { current++; } IRoute route = changed_solution.Add(current); used[current] = true; int current_size = size - 1; int previous = current; while (current_size > 0) { // choose the next customer. current = solution.Next(current); if (used[current]) { double neighbour_weight = double.MaxValue; foreach (int nn in problem.Get10NearestNeighbours(previous)) { if (!used[nn]) { double potential_weight = problem.WeightMatrix[previous][current]; if (potential_weight < neighbour_weight) { current = nn; neighbour_weight = potential_weight; } //break; } } int used_count = 0; while (used[current]) { current++; used_count++; if (current == solution.Size) { current = 0; } //if (used_count == problem.Size) //{ // break; //} } } // set the next array. //route.InsertAfterAndRemove(previous, current, route.First); route.InsertAfter(previous, current); used[current] = true; previous = current; current_size--; } if (!changed_solution.IsValid()) { throw new Exception(); } } return(changed_solution); }
/// <summary> /// Executes a solver procedure. /// </summary> /// <param name="problem"></param> /// <returns></returns> internal override MaxTimeSolution Solve(MaxTimeProblem problem) { // create the solution. var solution = new MaxTimeSolution(problem.Size); // keep placing customer until none are left. var customers = new List <int>(problem.Customers); customers.RemoveAt(0); double max = problem.Max.Value - (problem.Max.Value * _deltaPercentage); // keep a list of cheapest insertions. IInsertionCosts costs = new BinaryHeapInsertionCosts(); double percentage = _thresholdPercentage; while (customers.Count > 0) { //// try and distribute the remaining customers if there are only a few left. //if (customers.Count < problem.Size * percentage) //{ // bool succes = true; // while (succes && customers.Count > 0) // { // succes = false; // CheapestInsertionResult best = new CheapestInsertionResult(); // best.Increase = float.MaxValue; // int best_idx = -1; // for (int route_idx = 0; route_idx < solution.Count; route_idx++) // { // IRoute route = solution.Route(route_idx); // CheapestInsertionResult result = // CheapestInsertionHelper.CalculateBestPlacement(problem, route, customers); // if (best.Increase > result.Increase) // { // best = result; // best_idx = route_idx; // } // } // IRoute best_route = solution.Route(best_idx); // double route_time = problem.Time(best_route); // if (route_time + best.Increase < max) // { // insert the customer. // best_route.InsertAfter(best.CustomerBefore, best.Customer); // customers.Remove(best.Customer); // this.Improve(problem, solution, max, best_idx); // succes = true; // } // } //} // select a customer using some heuristic. int customer = this.SelectSeed(problem, problem.MaxTimeCalculator, solution, customers); customers.Remove(customer); // start a route r. IRoute currentRoute = solution.Add(customer); solution[solution.Count - 1] = 0; while (customers.Count > 0) { // calculate the best placement. CheapestInsertionResult result; if (_useSeedCost) { // use the seed cost; the cost to the seed customer. result = CheapestInsertionHelper.CalculateBestPlacement(problem, currentRoute, customers, customer, 0.7); // calculate the 'real' increase. result.Increase = (problem.WeightMatrix[result.CustomerBefore][result.Customer] + problem.WeightMatrix[result.Customer][result.CustomerAfter]) - problem.WeightMatrix[result.CustomerBefore][result.CustomerAfter]; } else { // just use cheapest insertion. result = CheapestInsertionHelper.CalculateBestPlacement(problem, currentRoute, customers, costs); } // calculate the new weight. solution[solution.Count - 1] = problem.Time(solution.Route(solution.Count - 1)); double potentialWeight = problem.MaxTimeCalculator.CalculateOneRouteIncrease(solution[solution.Count - 1], result.Increase); // cram as many customers into one route as possible. if (potentialWeight < max) { // insert the customer, it is customers.Remove(result.Customer); currentRoute.InsertAfter(result.CustomerBefore, result.Customer); // free some memory in the costs list. costs.Remove(result.CustomerBefore, result.CustomerAfter); // update the cost of the route. solution[solution.Count - 1] = potentialWeight; // improve if needed. if (((problem.Size - customers.Count) % _k) == 0) { // an improvement is decided. // apply the inter-route improvements. var copy = (solution.Clone() as MaxTimeSolution); int countBefore = solution.Route(solution.Count - 1).Count; solution[solution.Count - 1] = this.ImproveIntraRoute(problem, solution.Route(solution.Count - 1), solution[solution.Count - 1]); if (!solution.IsValid()) { throw new Exception(); } int countAfter = solution.Route(solution.Count - 1).Count; if (countAfter != countBefore) { throw new Exception(); } // also to the inter-improvements. currentRoute = this.Improve(problem, solution, max, solution.Count - 1); } } else {// ok we are done! this.Improve(problem, solution, max, solution.Count - 1); // break the route. break; } } } // remove empty routes. for (int routeIdx = solution.Count - 1; routeIdx >= 0; routeIdx--) { if (solution.Route(routeIdx).IsEmpty) { solution.Remove(routeIdx); } } return(solution); }
/// <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> /// Generates individuals based on a random first customer for each route. /// </summary> /// <param name="solver"></param> /// <returns></returns> public Individual <List <Genome>, Problem, Fitness> Generate( Solver <List <Genome>, Problem, Fitness> solver) { Problem problem = solver.Problem; DynamicAsymmetricMultiRoute multi_route = new DynamicAsymmetricMultiRoute(problem.Size, true); // create the problem for the genetic algorithm. List <int> customers = new List <int>(); for (int customer = problem.Depots.Count; customer < problem.Size; customer++) { customers.Add(customer); } CheapestInsertionHelper helper = new CheapestInsertionHelper(); List <double> weights = new List <double>(); for (int i = 0; i < problem.Depots.Count; i++) { multi_route.Add(i); weights.Add(0); } int k = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(problem.Depots.Count); // keep placing customer until none are left. while (customers.Count > 0) { k = (k + 1) % problem.Depots.Count; // use best placement to generate a route. IRoute current_route = multi_route.Route(k); //Console.WriteLine("Starting new route with {0}", customer); while (customers.Count > 0) { // calculate the best placement. CheapestInsertionResult result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers); if (result.CustomerAfter == -1 || result.CustomerBefore == -1) { customers.Remove(result.Customer); continue; } // calculate the new weight. customers.Remove(result.Customer); //current_route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter); current_route.InsertAfter(result.CustomerBefore, result.Customer); weights[k] += result.Increase + 15 * 60; if (weights[k] == weights.Max()) { break; } } } for (int i = 0; i < problem.Depots.Count; i++) { multi_route.RemoveCustomer(i); } List <Genome> genomes = new List <Genome>(); genomes.Add(Genome.CreateFrom(multi_route)); Individual <List <Genome>, Problem, Fitness> individual = new Individual <List <Genome>, Problem, Fitness>(genomes); //individual.Initialize(); return(individual); }
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)); }
/// <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> /// Executes a solver procedure. /// </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); // keep placing customer until none are left. List <int> customers = new List <int>(problem.Customers); while (customers.Count > 0) { // select a customer using some heuristic. int customer_idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(customers.Count); int customer = customers[customer_idx]; customers.Remove(customer); // start a route r. double current_route_weight = 0; IRoute current_route = solution.Add(customer); //Console.WriteLine("Starting new route with {0}", customer); while (customers.Count > 0) { // calculate the best placement. CheapestInsertionResult result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers); // calculate the new weight. double potential_weight = calculator.CalculateOneRouteIncrease(current_route_weight, result.Increase); // cram as many customers into one route as possible. if (potential_weight < problem.Max.Value) { // insert the customer, it is customers.Remove(result.Customer); //current_route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter); current_route.InsertAfter(result.CustomerBefore, result.Customer); current_route_weight = potential_weight; //// improve if needed. ////if (improvement_probalitity > OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(1)) //if (((problem.Size - customers.Count) % _k) == 0) //{ // an improvement is descided. // current_route_weight = this.ImproveIntraRoute(problem, // current_route, current_route_weight); //} } else {// ok we are done! //// apply the intra-route heuristics. //for (int route_idx = 0; route_idx < solution.Count - 1; route_idx++) //{ // apply the intra-route heurstic between the new and all existing routes. // this.ImproveInterRoute(problem, solution.Route(route_idx), current_route); //} //// apply the inter-route heuristics. //for (int route_idx = 0; route_idx < solution.Count; route_idx++) //{ // apply heurstic for each route. // IRoute route = solution.Route(route_idx); // this.ImproveIntraRoute(problem, current_route, current_route_weight); //} // break the route. break; } } } return(solution); }
/// <summary> /// Executes a solver procedure. /// </summary> /// <param name="problem"></param> /// <returns></returns> internal override MaxTimeSolution Solve(MaxTimeProblem problem) { // create the solution. MaxTimeSolution solution = new MaxTimeSolution(problem.Size, true); // keep placing customer until none are left. List <int> customers = new List <int>(problem.Customers); double max = problem.Max.Value - (problem.Max.Value * _delta_percentage); // keep a list of cheapest insertions. IInsertionCosts costs = new BinaryHeapInsertionCosts(); double percentage = _threshold_percentage; while (customers.Count > 0) { // try and distribute the remaining customers if there are only a few left. if (customers.Count < problem.Size * percentage) { bool succes = true; while (succes && customers.Count > 0) { succes = false; CheapestInsertionResult best = new CheapestInsertionResult(); best.Increase = float.MaxValue; int best_idx = -1; for (int route_idx = 0; route_idx < solution.Count; route_idx++) { IRoute route = solution.Route(route_idx); CheapestInsertionResult result = CheapestInsertionHelper.CalculateBestPlacement(problem, route, customers); if (best.Increase > result.Increase) { best = result; best_idx = route_idx; } } IRoute best_route = solution.Route(best_idx); double route_time = problem.Time(best_route); if (route_time + best.Increase < max) { // insert the customer. best_route.InsertAfter(best.CustomerBefore, best.Customer); customers.Remove(best.Customer); this.Improve(problem, solution, max, best_idx); succes = true; } } } // select a customer using some heuristic. if (customers.Count > 0) { // select a customer using some heuristic. int customer = -1; if (_use_seed) { // use a seeding heuristic. customer = this.SelectSeed(problem, problem.MaxTimeCalculator, solution, customers); } else { // just select a random customer. customer = customers[Math.Random.StaticRandomGenerator.Get().Generate(customers.Count)]; } customers.Remove(customer); // start a route r. IRoute current_route = solution.Add(customer); solution[solution.Count - 1] = 0; while (customers.Count > 0) { //OsmSharp.IO.Output.OutputStreamHost.WriteLine("{0}/{1} placed!", // customers.Count, problem.Size); // calculate the best placement. CheapestInsertionResult result; if (_use_seed_cost) { // use the seed cost; the cost to the seed customer. result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers, customer, _lambda); // calculate the 'real' increase. result.Increase = (problem.WeightMatrix[result.CustomerBefore][result.Customer] + problem.WeightMatrix[result.Customer][result.CustomerAfter]) - problem.WeightMatrix[result.CustomerBefore][result.CustomerAfter]; } else { // just use cheapest insertion. result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, customers, costs); } // calculate the new weight. solution[solution.Count - 1] = problem.Time(solution.Route(solution.Count - 1)); double potential_weight = problem.MaxTimeCalculator.CalculateOneRouteIncrease(solution[solution.Count - 1], result.Increase); // cram as many customers into one route as possible. if (potential_weight < max) { // insert the customer, it is customers.Remove(result.Customer); current_route.InsertAfter(result.CustomerBefore, result.Customer); // free some memory in the costs list. costs.Remove(result.CustomerBefore, result.CustomerAfter); // update the cost of the route. solution[solution.Count - 1] = potential_weight; // improve if needed. if (((problem.Size - customers.Count) % _k) == 0) { // an improvement is descided. // apply the inter-route improvements. int count_before = solution.Route(solution.Count - 1).Count; solution[solution.Count - 1] = this.ImproveIntraRoute(problem, current_route, solution[solution.Count - 1]); if (!solution.IsValid()) { throw new Exception(); } int count_after = solution.Route(solution.Count - 1).Count; // also to the inter-improvements. current_route = this.Improve(problem, solution, max, solution.Count - 1); } } else {// ok we are done! this.Improve(problem, solution, max, solution.Count - 1); // break the route. break; } } //else //{// ok we are done! // solution[solution.Count - 1] = this.ImproveIntraRoute(problem, // current_route, solution[solution.Count - 1]); // if (!solution.IsValid()) // { // throw new Exception(); // } // int count_after = solution.Route(solution.Count - 1).Count; // this.Improve(problem, solution, max, solution.Count - 1); // // break the route. // break; //} } } // remove empty routes. for (int route_idx = solution.Count - 1; route_idx >= 0; route_idx--) { if (solution.Route(route_idx).IsEmpty) { solution.Remove(route_idx); } } return(solution); }
/// <summary> /// Tests adding customers. /// </summary> public void DoTestAdd() { IMultiRoute multiRoute = this.BuildRoute(true); Assert.AreEqual(0, multiRoute.Count); int count = 10; int routes = 3; for (int routeIdx = 0; routeIdx < routes; routeIdx++) { int customerStart = (routeIdx * count); IRoute route = multiRoute.Add(customerStart); Assert.AreEqual(1, route.Count); Assert.AreEqual(false, route.IsEmpty); Assert.AreEqual(true, route.IsRound); for (int customer = customerStart + 1; customer < customerStart + count; customer++) { route.InsertAfter(customer - 1, customer); Assert.AreEqual(customer - customerStart + 1, route.Count); Assert.AreEqual(false, route.IsEmpty); Assert.AreEqual(true, route.IsRound); Assert.AreEqual(customerStart, route.First); Assert.AreEqual(customerStart, route.Last); } for (int customer = customerStart + 1; customer < customerStart + count - 1; customer++) { Assert.IsTrue(route.Contains(customer)); Assert.IsTrue(route.Contains(customer, customer + 1)); } Assert.IsTrue(route.Contains(customerStart + count - 1)); Assert.IsTrue(route.Contains(customerStart + count - 1, customerStart)); Assert.AreEqual(routeIdx + 1, multiRoute.Count); Assert.AreEqual(count * (routeIdx + 1), multiRoute.Size); } // test with initializing the routes empty. multiRoute = this.BuildRoute(true); Assert.AreEqual(0, multiRoute.Count); for (int routeIdx = 0; routeIdx < routes; routeIdx++) { int customerStart = (routeIdx * count); IRoute route = multiRoute.Add(); Assert.AreEqual(0, route.Count); Assert.AreEqual(true, route.IsEmpty); Assert.AreEqual(true, route.IsRound); for (int customer = customerStart; customer < customerStart + count; customer++) { route.InsertAfter(customer - 1, customer); Assert.AreEqual(customer - customerStart + 1, route.Count); Assert.AreEqual(false, route.IsEmpty); Assert.AreEqual(true, route.IsRound); Assert.AreEqual(customerStart, route.First); Assert.AreEqual(customerStart, route.Last); } for (int customer = customerStart; customer < customerStart + count - 1; customer++) { Assert.IsTrue(route.Contains(customer)); Assert.IsTrue(route.Contains(customer, customer + 1)); } Assert.IsTrue(route.Contains(customerStart + count - 1)); Assert.IsTrue(route.Contains(customerStart + count - 1, customerStart)); Assert.AreEqual(routeIdx + 1, multiRoute.Count); Assert.AreEqual(count * (routeIdx + 1), multiRoute.Size); } }
/// <summary> /// Re-inserts a customer in the route. /// </summary> /// <param name="weights"></param> /// <param name="route"></param> /// <param name="customer"></param> /// <param name="difference"></param> /// <returns></returns> public static bool InsertOne(IProblemWeights weights, IRoute route, int customer, out double difference) { // calculate placement. CheapestInsertionResult result = CheapestInsertionHelper.CalculateBestPlacement(weights, route, customer); // place the customer. if (result.CustomerAfter >= 0 && result.CustomerBefore >= 0) { //route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter); route.InsertAfter(result.CustomerBefore, result.Customer); difference = -(weights.WeightMatrix[result.CustomerBefore][result.CustomerAfter]) + (weights.WeightMatrix[result.CustomerBefore][result.Customer]) + (weights.WeightMatrix[result.Customer][result.CustomerAfter]); return true; } difference = 0; return false; }
/// <summary> /// Does the mutation. /// </summary> /// <param name="solver"></param> /// <param name="mutating"></param> /// <returns></returns> public Individual <MaxTimeSolution, MaxTimeProblem, Fitness> Mutate( Solver <MaxTimeSolution, MaxTimeProblem, Fitness> solver, Individual <MaxTimeSolution, MaxTimeProblem, Fitness> mutating) { // get the route information. MaxTimeSolution multi_route = mutating.Genomes.Clone() as MaxTimeSolution; if (multi_route.Count > 1) { // TODO: Maybe add some extra code for the the route-count is very low and chances of collisions are big. // TODO: investigate what is more expensive, and extra random generation or creating a list and remove items. // http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle // select a route. int source_route_idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(multi_route.Count); int target_route_idx = -1; do { target_route_idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(multi_route.Count); } while (source_route_idx == target_route_idx); int source_count = multi_route.Sizes[source_route_idx]; int target_count = multi_route.Sizes[target_route_idx]; if (target_count > 0 && source_count > 3) { // take a part out of the orginal. int size = (int)OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(source_count); int source_location = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(source_count); int first = source_location - (size / 2); if (first < 0) { first = 0; } //first = multi_route.StartOf(source_route_idx) + first; int last = source_location + (size / 2); if (last > source_count - 1) { last = source_count - 1; } //last = multi_route.StartOf(source_route_idx) + last; int idx = -1; IRoute source = multi_route.Route(source_route_idx); List <int> part_of_orginal = new List <int>(); foreach (int customer in source) { idx++; if (idx >= first && idx <= last) { part_of_orginal.Add(customer); } } // remove from the source. foreach (int customer in part_of_orginal) { multi_route.RemoveCustomer(customer); } // place it somewhere in the target. if (part_of_orginal.Count > 0) { IRoute target = multi_route.Route(target_route_idx); CheapestInsertionResult route_placement = CheapestInsertionHelper.CalculateBestPlacement( solver.Problem, target, part_of_orginal[0], part_of_orginal[part_of_orginal.Count - 1]); int from = route_placement.CustomerBefore; foreach (int customer in part_of_orginal) { target.InsertAfter(from, customer); //target.InsertAfterAndRemove(from, customer, -1); from = customer; } } } } return(new Individual <MaxTimeSolution, MaxTimeProblem, Fitness>(multi_route)); }
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); }
private void FillRoutes(MaxTimeCalculator calculator, MaxTimeSolution route1, MaxTimeSolution solution, MaxTimeProblem problem) { double[] weights = new double[solution.Count]; // insert all non-placed customers in the order of the first route. HashSet <int> unplaced = new HashSet <int>(); for (int route_idx = 0; route_idx < route1.Count; route_idx++) { IRoute route1_route = route1.Route(route_idx); foreach (int customer in route1_route) { if (!solution.Contains(customer)) { unplaced.Add(customer); } } } for (int idx = 0; idx < solution.Count; idx++) { IRoute route = solution.Route(idx); weights[idx] = calculator.CalculateOneRoute(route); } // insert all non-placed customers in the order of the first route. //for (int route_idx = 0; route_idx < route1.Count; route_idx++) //{ // IRoute route1_route = route1.Route(route_idx); // foreach (int customer in route1_route) // { // if (!solution.Contains(customer)) // { while (unplaced.Count > 0) { int customer = unplaced.First <int>(); // try reinsertion. CheapestInsertionResult result = new CheapestInsertionResult(); result.Increase = double.MaxValue; int target_idx = -1; CheapestInsertionResult unlimited_result = new CheapestInsertionResult(); unlimited_result.Increase = double.MaxValue; int unlimited_target_idx = -1; for (int idx = 0; idx < solution.Count; idx++) { IRoute route = solution.Route(idx); CheapestInsertionResult current_result = CheapestInsertionHelper.CalculateBestPlacement(problem.Weights, route, customer); if (current_result.Increase < result.Increase) { if (weights[idx] + current_result.Increase < problem.Max.Value) { target_idx = idx; result = current_result; if (result.Increase <= 0) { break; } } } if (current_result.Increase < unlimited_result.Increase) { unlimited_target_idx = idx; unlimited_result = current_result; } } if (target_idx < 0) { result = unlimited_result; target_idx = unlimited_target_idx; } // get the target route and insert. IRoute target_route = solution.Route(target_idx); weights[target_idx] = weights[target_idx] + result.Increase; //target_route.InsertAfterAndRemove(result.CustomerBefore, result.Customer, result.CustomerAfter); target_route.InsertAfter(result.CustomerBefore, result.Customer); unplaced.Remove(result.Customer); ////solution.ToString(); //if (!solution.IsValid()) //{ // throw new Exception(); //} } // } //} }
/// <summary> /// Test removing customers. /// </summary> public void DoTestRemove() { // create a new empty route. const int count = 100; IRoute route = this.BuildRoute(0, true); var customers = new List <int>(); if (route != null) { // this part needs testing! customers.Add(0); for (int customer = 1; customer < count; customer++) { route.InsertAfter(customer - 1, customer); //route.InsertAfterAndRemove(customer - 1, customer, -1); customers.Add(customer); } // remove customers. while (customers.Count > 0) { int customerIdx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate( customers.Count); int customer = customers[customerIdx]; customers.RemoveAt(customerIdx); route.Remove(customer); Assert.AreEqual(customers.Count, route.Count); Assert.AreEqual(customers.Count == 0, route.IsEmpty); Assert.AreEqual(true, route.IsRound); Assert.AreEqual(route.Last, route.First); } } route = this.BuildRoute(true); customers = new List <int>(); 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); customers.Add(customer); } // remove customers. while (customers.Count > 0) { int customerIdx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate( customers.Count); int customer = customers[customerIdx]; customers.RemoveAt(customerIdx); route.Remove(customer); Assert.AreEqual(customers.Count, route.Count); Assert.AreEqual(customers.Count == 0, route.IsEmpty); Assert.AreEqual(true, route.IsRound); Assert.AreEqual(route.Last, route.First); } } }
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(); }