/// <summary> /// Selects a new seed customer. /// </summary> /// <param name="problem"></param> /// <param name="calculator"></param> /// <param name="solution"></param> /// <param name="customers"></param> /// <returns></returns> private int SelectSeed(MaxTimeProblem problem, MaxTimeCalculator calculator, MaxTimeSolution solution, List <int> customers) { int selected_customer = -1; double max_distance = double.MaxValue; foreach (int customer_to_check in customers) { SortedDictionary <double, List <int> > neighbours = new SortedDictionary <double, List <int> >(); for (int idx = 0; idx < customers.Count; idx++) { int customer = customers[idx]; if (customer != customer_to_check) { double weight = problem.WeightMatrix[customer_to_check][customer] + problem.WeightMatrix[customer_to_check][customer]; List <int> customers_list = null; if (!neighbours.TryGetValue(weight, out customers_list)) { customers_list = new List <int>(); neighbours.Add(weight, customers_list); } customers_list.Add(customer); } } double nearest_neighbour_average = 0; int neighbour_count = 20; int neighbour_counted = 0; foreach (KeyValuePair <double, List <int> > pair in neighbours) { foreach (int customer in pair.Value) { if (neighbour_counted < neighbour_count) { neighbour_counted++; nearest_neighbour_average = nearest_neighbour_average + pair.Key; } else { break; } } } if (max_distance > nearest_neighbour_average) { max_distance = nearest_neighbour_average; selected_customer = customer_to_check; } } return(selected_customer); }
/// <summary> /// Selects a new seed customer. /// </summary> /// <param name="problem"></param> /// <param name="calculator"></param> /// <param name="solution"></param> /// <param name="customers"></param> /// <returns></returns> private int SelectSeed(MaxTimeProblem problem, MaxTimeCalculator calculator, MaxTimeSolution solution, List <int> customers) { // select the customer farthest from the depot. int selectedCustomer = -1; double maxDistance = double.MinValue; foreach (int customerToCheck in customers) { double distance = problem.WeightMatrix[0][customerToCheck] + problem.WeightMatrix[customerToCheck][0]; if (distance > maxDistance) { maxDistance = distance; selectedCustomer = customerToCheck; } } return(selectedCustomer); }
/// <summary> /// Executes a solver procedure. /// </summary> /// <param name="problem"></param> /// <returns></returns> internal override MaxTimeSolution Solve(MaxTimeProblem problem) { MaxTimeCalculator calculator = new MaxTimeCalculator(problem); // get the seed customers. ICollection<int> seeds = _seed_selector.SelectSeeds( problem, _k); double[] weights = new double[seeds.Count]; // start the seed routes. List<int> selectable_customers = problem.Customers; MaxTimeSolution routes = new MaxTimeSolution( problem.Size, true); foreach (int seed in seeds) { routes.Add(seed); selectable_customers.Remove(seed); } if (!routes.IsValid()) { throw new Exception(); } // keep a list of cheapest insertions. IInsertionCosts costs = new BinaryHeapInsertionCosts(); // keep looping until all customers have been placed. while (selectable_customers.Count > 0) { // try and place into every route. CheapestInsertionResult best_result = new CheapestInsertionResult(); best_result.Increase = float.MaxValue; int best_route_idx = -1; CheapestInsertionResult best_result_above_max = new CheapestInsertionResult(); best_result_above_max.Increase = float.MaxValue; int best_route_above_max_idx = -1; for (int route_idx = 0; route_idx < routes.Count; route_idx++) { IRoute current_route = routes.Route(route_idx); // choose the next customer. CheapestInsertionResult result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, selectable_customers, costs); if (result.Customer == result.CustomerAfter) { throw new Exception(); } // get the current weight double weight = weights[route_idx]; if (result.Increase < best_result.Increase) { if (weight + result.Increase + calculator.DeliveryTime < problem.Max.Value) { // route will still be inside bounds. best_result = result; best_route_idx = route_idx; } else { // route will become above max. if (result.Increase < best_result_above_max.Increase) { best_result_above_max = result; best_route_above_max_idx = route_idx; } } } } // do the placement if a placement is found without max violation. // else do the placement in the above max route. CheapestInsertionResult placement_result = new CheapestInsertionResult(); placement_result.Increase = double.MaxValue; int placement_result_idx = -1; if (best_route_idx >= 0) { // best placement found. placement_result = best_result; placement_result_idx = best_route_idx; } else { // best placement found but only above max. placement_result = best_result_above_max; placement_result_idx = best_route_above_max_idx; } // do the actual placement. weights[placement_result_idx] = calculator.CalculateOneRouteIncrease( weights[placement_result_idx], placement_result.Increase); selectable_customers.Remove(placement_result.Customer); //routes.Route(placement_result_idx).InsertAfterAndRemove( // placement_result.CustomerBefore, placement_result.Customer, placement_result.CustomerAfter); routes.Route(placement_result_idx).InsertAfter( placement_result.CustomerBefore, placement_result.Customer); if (!routes.IsValid()) { throw new Exception(); } } return routes; }
/// <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; }
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)); }
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(); //} } // } //} }
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> /// 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 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.Tools.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.Tools.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> /// Selects a new seed customer. /// </summary> /// <param name="problem"></param> /// <param name="calculator"></param> /// <param name="solution"></param> /// <param name="customers"></param> /// <returns></returns> private int SelectSeed(MaxTimeProblem problem, MaxTimeCalculator calculator, MaxTimeSolution solution, List<int> customers) { int selected_customer = -1; double max_distance = double.MaxValue; foreach (int customer_to_check in customers) { SortedDictionary<double, List<int>> neighbours = new SortedDictionary<double, List<int>>(); for (int idx = 0; idx < customers.Count; idx++) { int customer = customers[idx]; if (customer != customer_to_check) { double weight = problem.WeightMatrix[customer_to_check][customer] + problem.WeightMatrix[customer_to_check][customer]; List<int> customers_list = null; if (!neighbours.TryGetValue(weight, out customers_list)) { customers_list = new List<int>(); neighbours.Add(weight, customers_list); } customers_list.Add(customer); } } double nearest_neighbour_average = 0; int neighbour_count = 20; int neighbour_counted = 0; foreach (KeyValuePair<double, List<int>> pair in neighbours) { foreach (int customer in pair.Value) { if (neighbour_counted < neighbour_count) { neighbour_counted++; nearest_neighbour_average = nearest_neighbour_average + pair.Key; } else { break; } } } if (max_distance > nearest_neighbour_average) { max_distance = nearest_neighbour_average; selected_customer = customer_to_check; } } return selected_customer; }
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)); OsmSharp.Logging.Log.TraceEvent("TSPPlacementSolver", TraceEventType.Information, builder.ToString()); return solution; }
/// <summary> /// Executes a solver procedure. /// </summary> /// <param name="problem"></param> /// <returns></returns> internal override MaxTimeSolution Solve(MaxTimeProblem problem) { MaxTimeCalculator calculator = new MaxTimeCalculator(problem); // get the seed customers. ICollection <int> seeds = _seed_selector.SelectSeeds( problem, _k); double[] weights = new double[seeds.Count]; // start the seed routes. List <int> selectable_customers = problem.Customers; MaxTimeSolution routes = new MaxTimeSolution( problem.Size, true); foreach (int seed in seeds) { routes.Add(seed); selectable_customers.Remove(seed); } if (!routes.IsValid()) { throw new Exception(); } // keep a list of cheapest insertions. IInsertionCosts costs = new BinaryHeapInsertionCosts(); // keep looping until all customers have been placed. while (selectable_customers.Count > 0) { // try and place into every route. CheapestInsertionResult best_result = new CheapestInsertionResult(); best_result.Increase = float.MaxValue; int best_route_idx = -1; CheapestInsertionResult best_result_above_max = new CheapestInsertionResult(); best_result_above_max.Increase = float.MaxValue; int best_route_above_max_idx = -1; for (int route_idx = 0; route_idx < routes.Count; route_idx++) { IRoute current_route = routes.Route(route_idx); // choose the next customer. CheapestInsertionResult result = CheapestInsertionHelper.CalculateBestPlacement(problem, current_route, selectable_customers, costs); if (result.Customer == result.CustomerAfter) { throw new Exception(); } // get the current weight double weight = weights[route_idx]; if (result.Increase < best_result.Increase) { if (weight + result.Increase + calculator.DeliveryTime < problem.Max.Value) { // route will still be inside bounds. best_result = result; best_route_idx = route_idx; } else { // route will become above max. if (result.Increase < best_result_above_max.Increase) { best_result_above_max = result; best_route_above_max_idx = route_idx; } } } } // do the placement if a placement is found without max violation. // else do the placement in the above max route. CheapestInsertionResult placement_result = new CheapestInsertionResult(); placement_result.Increase = double.MaxValue; int placement_result_idx = -1; if (best_route_idx >= 0) { // best placement found. placement_result = best_result; placement_result_idx = best_route_idx; } else { // best placement found but only above max. placement_result = best_result_above_max; placement_result_idx = best_route_above_max_idx; } // do the actual placement. weights[placement_result_idx] = calculator.CalculateOneRouteIncrease( weights[placement_result_idx], placement_result.Increase); selectable_customers.Remove(placement_result.Customer); //routes.Route(placement_result_idx).InsertAfterAndRemove( // placement_result.CustomerBefore, placement_result.Customer, placement_result.CustomerAfter); routes.Route(placement_result_idx).InsertAfter( placement_result.CustomerBefore, placement_result.Customer); if (!routes.IsValid()) { throw new Exception(); } } return(routes); }
/// <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); }
/// <summary> /// Selects a new seed customer. /// </summary> /// <param name="problem"></param> /// <param name="calculator"></param> /// <param name="solution"></param> /// <param name="customers"></param> /// <returns></returns> private int SelectSeed(MaxTimeProblem problem, MaxTimeCalculator calculator, MaxTimeSolution solution, List<int> customers) { // select the customer farthest from the depot. int selectedCustomer = -1; double maxDistance = double.MinValue; foreach (int customerToCheck in customers) { double distance = problem.WeightMatrix[0][customerToCheck] + problem.WeightMatrix[customerToCheck][0]; if (distance > maxDistance) { maxDistance = distance; selectedCustomer = customerToCheck; } } return selectedCustomer; }