/// <summary> /// Applies this operator. /// </summary> public bool Apply(TSProblem problem, TSPObjective objective, Tour solution, out float delta) { if (problem.Weights.Length <= 2) { delta = 0; return(false); } var before = objective.Calculate(problem, solution); var weights = problem.Weights; var turnPenalties = problem.TurnPenalties; delta = 0; // test switching directions in random order. if (_pool == null || solution.Count != _pool.Size) { // create a new pool. _pool = new RandomPool(solution.Count); } else { // just reset the existing one. _pool.Reset(); } var i = _n; var toInsert = new List <int>(); while (_pool.MoveNext() && i > 0) { i--; var currentId = _pool.Current; var current = solution.GetDirectedId(currentId); if (current != Constants.NOT_SET) { if (current != solution.First && current != solution.Last && solution.Remove(current)) { toInsert.Add(current); } } } foreach (var current in toInsert) { CheapestInsertionDirectedHelper.InsertCheapestDirected(solution, weights, turnPenalties, DirectedHelper.ExtractId(current)); } var after = objective.Calculate(problem, solution); delta = after - before; return(delta < 0); }
/// <summary> /// Solves the given problem. /// </summary> /// <returns></returns> public sealed override Tour Solve(STSProblem problem, STSPObjective objective, out STSPFitness fitness) { // generate empty route based on problem definition. var route = problem.CreateEmptyTour(); fitness = new STSPFitness() { Weight = 0, Customers = 1 }; // generate random pool to select customers from. if (_randomPool == null || _randomPool.Size < problem.Weights.Length) { _randomPool = new RandomPool(problem.Weights.Length / 2); } else { _randomPool.Reset(); } // keep adding customers until no more space is left or no more customers available. while (_randomPool.MoveNext()) { var customer = _randomPool.Current; if (customer == DirectedHelper.ExtractId(route.First) || (route.Last.HasValue && customer == DirectedHelper.ExtractId(route.Last.Value))) { // customer is first or last. continue; } var cost = CheapestInsertionDirectedHelper.InsertCheapestDirected(route, problem.Weights, problem.TurnPenalties, customer, problem.Max - fitness.Weight); if (cost > 0) { fitness.Customers++; fitness.Weight += cost; } } // calculate fitness. fitness = objective.Calculate(problem, route); return(route); }
/// <summary> /// Solves the given problem. /// </summary> /// <returns></returns> public sealed override Tour Solve(STSProblem problem, STSPObjective objective, out STSPFitness fitness) { // generate random pool to select customers from. if (_randomPool == null || _randomPool.Size < problem.Weights.Length) { _randomPool = new RandomPool(problem.Weights.Length); } else { _randomPool.Reset(); } // keep adding customers until no more space is left or no more customers available. var tour = problem.CreateEmptyTour(); fitness = new STSPFitness() { Weight = 0, Customers = 1 }; while (_randomPool.MoveNext()) { var customer = _randomPool.Current; if (customer == problem.First || customer == problem.Last) { continue; } Pair location; var cost = CheapestInsertionHelper.CalculateCheapest(tour, problem.Weights, customer, out location); if (cost + fitness.Weight < problem.Max) { tour.InsertAfter(location.From, customer); fitness.Weight = fitness.Weight + cost; fitness.Customers = fitness.Customers + 1; } } // calculate fitness. fitness = objective.Calculate(problem, tour); return(tour); }
/// <summary> /// Applies this operator. /// </summary> public bool Apply(TSProblem problem, TSPObjective objective, Tour solution, out float delta) { if (problem.Weights.Length <= 2) { delta = 0; return(false); } var weights = problem.Weights; delta = 0; // test switching directions in random order. if (_pool == null || solution.Count != _pool.Size) { // create a new pool. _pool = new RandomPool(solution.Count); } else { // just reset the existing one. _pool.Reset(); } while (_pool.MoveNext()) { var previous = solution.GetDirectedId(_pool.Current); var previousDepartureId = DirectedHelper.ExtractDepartureId(previous); var current = solution.GetNeigbour(previous); if (current == Constants.NOT_SET) { // last of open. continue; } var next = solution.GetNeigbour(current); var nextArrivalId = Constants.NOT_SET; if (next != Constants.NOT_SET) { nextArrivalId = DirectedHelper.ExtractArrivalId(next); } int currentTurn, currentId, currentArrivalId, currentDepartureId; DirectedHelper.ExtractAll(current, out currentArrivalId, out currentDepartureId, out currentId, out currentTurn); var weightBefore = weights[previousDepartureId][currentArrivalId]; var weightAfter = float.MaxValue; var newDirectedId = Constants.NOT_SET; if (next == Constants.NOT_SET) { // there is no next, only one option here: // 0 or 1: arrival id offset = 0 OR // 2 or 3: arrival id offset = 1 if (currentArrivalId % 2 == 0) { // check turn = 2. weightAfter = weights[previousDepartureId][currentArrivalId + 1]; if (weightAfter < weightBefore) { // do the switch. newDirectedId = DirectedHelper.BuildDirectedId(currentId, 2); } } else { // check turn = 0 weightAfter = weights[previousDepartureId][currentArrivalId - 1]; if (weightAfter < weightBefore) { // do the switch. newDirectedId = DirectedHelper.BuildDirectedId(currentId, 0); } } } else { // three options left, excluding the current one of 4. weightBefore += weights[currentDepartureId][nextArrivalId]; weightBefore += problem.TurnPenalties[currentTurn]; currentArrivalId = currentArrivalId - (currentArrivalId % 2); currentDepartureId = currentDepartureId - (currentDepartureId % 2); for (var i = 0; i < 4; i++) { if (i == currentTurn) { continue; } int arrivalOffset, departureOffset; DirectedHelper.ExtractOffset(i, out arrivalOffset, out departureOffset); var newWeightAfter = weights[previousDepartureId][currentArrivalId + arrivalOffset] + weights[currentDepartureId + departureOffset][nextArrivalId] + problem.TurnPenalties[i]; if (newWeightAfter < weightAfter && newWeightAfter < weightBefore) { newDirectedId = DirectedHelper.BuildDirectedId(currentId, i); weightAfter = newWeightAfter; } } } // switch if a new directed if was found. if (newDirectedId != Constants.NOT_SET) { delta = weightAfter - weightBefore; // negative when improvement. solution.Replace(current, newDirectedId); } } return(delta < 0); }