/// <summary> /// Tries to improve the existing route using CI and return true if succesful. /// </summary> /// <param name="problem"></param> /// <param name="route"></param> /// <param name="difference"></param> /// <returns></returns> public bool Improve(IProblemWeights problem, IRoute route, out double difference) { bool improvement = false; difference = 0; if (route.Count > 3) { // loop over all customers and try cheapest insertion. for (int customer = 0; customer < problem.Size; customer++) { //string route_string = route.ToString(); //IRoute previous = route.Clone() as IRoute; if (route.Contains(customer)) { // remove customer and keep position. int next = route.GetNeigbours(customer)[0]; route.Remove(customer); // insert again. ArbitraryInsertionSolver.InsertOne(problem, route, customer, out difference); if (!route.IsValid()) { throw new Exception(); } if (route.GetNeigbours(customer)[0] != next && difference < 0) { // another customer was found as the best, improvement is succesful. improvement = true; break; } } } } return(improvement); }
/// <summary> /// Does the actual solving. /// </summary> /// <param name="problem"></param> /// <returns></returns> protected override IRoute DoSolve(IProblem problem) { // convert to a symetric problem if needed. IProblem _problem = problem; if (!_problem.Symmetric) { _problem = Convertor.ConvertToSymmetric(_problem); _was_asym = true; } // create the list of customers. _customers = new List<int>(); for (int customer = 0; customer < _problem.Size; customer++) { _customers.Add(customer); } _sparse_set = SparseSetHelper.CreateNearestNeighourSet(_problem, _customers, _customers.Count / 10); //_sparse_set = SparseSetHelper.CreateNonSparseSet(_problem, _customers); // construct a route from the customers. //FixedSymmetricRoute init_route = new FixedSymmetricRoute(_customers); // construct a random route using best-placement. ArbitraryInsertionSolver bp_solver = new ArbitraryInsertionSolver(); IRoute bp_route = bp_solver.Solve(_problem); FixedSymmetricRoute init_route = new FixedSymmetricRoute(bp_route); double init_route_weight = LinKernighanSolver.Weight(_problem, init_route); RouteFound route = new RouteFound() { Route = init_route, RouteWeight = init_route_weight }; OsmSharp.Logging.Log.TraceEvent("LinKernighanSolver", Logging.TraceEventType.Information, "Route {0}:{1}", route.Route.ToString(), route.RouteWeight); // step 2. EdgeSet X = new EdgeSet(); EdgeSet Y = new EdgeSet(); IList<int> untried_t_1 = new List<int>(route.Route); while (untried_t_1.Count > 0) { // select t1. int t_1 = untried_t_1[0]; untried_t_1.RemoveAt(0); // search route with t_1. RouteFound t_1_route = this.AfterSelectt1(_problem, route, X, Y, t_1); // select the better route. if (t_1_route.RouteWeight < route.RouteWeight) { untried_t_1 = new List<int>(route.Route); route = RouteFound.SelectBest(route, t_1_route); X = new EdgeSet(); Y = new EdgeSet(); } } // step 2 and step 12. // convert back to asym solution if needed. //result.RemoveAt(result.Count - 1); if (_was_asym) { return this.ConvertToASymRoute(new List<int>(route.Route)); } return route.Route; }
/// <summary> /// Returns a solution found using best-placement. /// </summary> /// <returns></returns> protected override IRoute DoSolve(IProblem problem) { // build the customer list to place. List <int> customers = null; if (_customers != null) { // copy the list of the given customers and keep this order. customers = new List <int>(_customers); } else { // generate some random route. customers = new List <int>(); List <int> customers_to_place = new List <int>(); for (int customer = 0; customer < problem.Size; customer++) { customers_to_place.Add(customer); } while (customers_to_place.Count > 0) { int idx = OsmSharp.Math.Random.StaticRandomGenerator.Get().Generate(customers_to_place.Count); customers.Add(customers_to_place[idx]); customers_to_place.RemoveAt(idx); } } // initialize the route based on the problem definition. IRoute route = null; double weight = double.MaxValue; if (problem.Symmetric) { // create a symmetric route that is dynamic and can accept new customers. if (problem.First.HasValue && problem.Last.HasValue && problem.First == problem.Last) { // route is a round. route = new DynamicSymmetricRoute(problem.First.Value); } else { // not a round. throw new NotImplementedException("No symmetric routes implemented that are not rounds!"); } } else { // create a asymmetric route that is dynamic and can accept new customers. if (problem.First.HasValue) { // the first customer is set. // test if the last customer is the same. if (!problem.Last.HasValue || problem.Last == problem.First) { // the route is a round. route = new DynamicAsymmetricRoute(customers.Count, problem.First.Value, true); // remove the first customer. customers.Remove(problem.First.Value); // find the customer that is farthest away and add it. int to = -1; weight = double.MinValue; for (int x = 0; x < customers.Count; x++) { if (x != problem.First.Value) { // only different customers. double current_weight = problem.WeightMatrix[x][problem.First.Value] + problem.WeightMatrix[problem.First.Value][x]; if (current_weight > weight) { // the current weight is better. to = x; weight = current_weight; } } } route.InsertAfter(problem.First.Value, to); customers.Remove(to); } else { // the route is not a round. route = new DynamicAsymmetricRoute(customers.Count, problem.First.Value, false); route.InsertAfter(problem.First.Value, problem.Last.Value); // remove the first customer. customers.Remove(problem.First.Value); customers.Remove(problem.Last.Value); } } else { // the first and last customer can be choosen randomly. // find two customers close together. int from = -1; int to = -1; for (int x = 0; x < customers.Count; x++) { for (int y = 0; y < customers.Count; y++) { if (x != y) { // only different customers. double current_weight = problem.WeightMatrix[x][y]; if (current_weight < weight) { // the current weight is better. from = x; to = y; weight = current_weight; if (weight == 0) { // no edge with less weight is going to be found. break; } } } } } route = new DynamicAsymmetricRoute(customers.Count, from, false); route.InsertAfter(from, to); // remove the first customer. customers.Remove(from); customers.Remove(to); } } // insert the rest of the customers. while (customers.Count > 0 && !_stopped) { // keep placing customer 0 until all customers are placed. int customer = customers[0]; customers.RemoveAt(0); // insert the customer at the best place. double difference; ArbitraryInsertionSolver.InsertOne(problem, route, customer, out difference); } return(route); }