/// <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> /// 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> /// 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; }