/// <summary> /// Applies this operator. /// </summary> public bool Apply(TSPTWProblem problem, TSPTWObjective objective, Tour solution, out float delta) { foreach (var c in solution.Triples()) { int betterDirectedId; bool switchDepartureId, switchedArrivalId; if (DirectedHelper.SwitchToBestTurn(c.Along, c.From, c.To, problem.Times, problem.TurnPenalties, out betterDirectedId, out switchDepartureId, out switchedArrivalId, out delta)) { // an improvement was found. solution.Replace(c.Along, betterDirectedId); if (switchDepartureId) { var newFromId = DirectedHelper.SwitchDepartureOffset(c.From); solution.Replace(c.From, newFromId); } if (switchedArrivalId) { var newToId = DirectedHelper.SwitchArrivalOffset(c.To); solution.Replace(c.To, newToId); } return(true); } } delta = 0; return(false); }
/// <summary> /// Optimizes the given part of the tour by choosing the best improvements in either the departureOffset or arrivalOffset of the first/last customers or the turns at any of the intermediate ones. /// </summary> private float OptimizePart(TSPTWProblem problem, List <int> part) { int turn1, arrivalId1, departureId1, id1; int turn2, arrivalId2, departureId2, id2; int turn3, arrivalId3, departureId3, id3; var delta = 0f; // the positive difference. var arrivalIdChange = -1; var departureIdChange = -1; var customerIdx = -1; var customerTurn = -1; // try changing the departureId. DirectedHelper.ExtractAll(part[0], out arrivalId1, out departureId1, out id1, out turn1); DirectedHelper.ExtractAll(part[1], out arrivalId2, out departureId2, out id2, out turn2); var weight = problem.TurnPenalties[turn1]; weight += problem.Times[departureId1][arrivalId2]; var new0 = DirectedHelper.SwitchDepartureOffset(part[0]); DirectedHelper.ExtractAll(new0, out arrivalId3, out departureId3, out id3, out turn3); var newWeight = problem.TurnPenalties[turn3]; newWeight += problem.Times[departureId3][arrivalId2]; if (newWeight < weight) { // there was an improvement found in changing the departure id. departureIdChange = DirectedHelper.ExtractDepartureId(new0); delta = newWeight - weight; } // try changing the arrivalId. DirectedHelper.ExtractAll(part[part.Count - 2], out arrivalId1, out departureId1, out id1, out turn1); DirectedHelper.ExtractAll(part[part.Count - 1], out arrivalId2, out departureId2, out id2, out turn2); weight = problem.TurnPenalties[turn2]; weight += problem.Times[departureId1][arrivalId2]; var newLast = DirectedHelper.SwitchArrivalOffset(part[part.Count - 1]); DirectedHelper.ExtractAll(newLast, out arrivalId3, out departureId3, out id3, out turn3); newWeight = problem.TurnPenalties[turn3]; newWeight += problem.Times[departureId1][arrivalId3]; if (newWeight < weight && delta < (newWeight - weight)) { // there was an improvement found in changing the arrival id. arrivalIdChange = DirectedHelper.ExtractDepartureId(newLast); departureIdChange = -1; delta = newWeight - weight; } for (var c = 1; c < part.Count - 1; c++) { var perviousDepartureId = DirectedHelper.ExtractDepartureId(part[c - 1]); DirectedHelper.ExtractAll(part[c], out arrivalId1, out departureId1, out id1, out turn1); var nextArrivalid = DirectedHelper.ExtractArrivalId(part[c + 1]); weight = problem.Times[perviousDepartureId][arrivalId1]; weight += problem.TurnPenalties[turn1]; weight += problem.Times[departureId1][nextArrivalid]; for (var t = 0; t < 3; t++) { if (t == turn1) { continue; } var newDirectedId = DirectedHelper.BuildDirectedId(id1, t); DirectedHelper.ExtractAll(newDirectedId, out arrivalId2, out departureId2, out id2, out turn2); newWeight = problem.Times[perviousDepartureId][arrivalId2]; newWeight += problem.TurnPenalties[turn2]; newWeight += problem.Times[departureId2][nextArrivalid]; if (newWeight < weight && delta < (newWeight - weight)) { // there was an improvement found in changing the turn. arrivalIdChange = -1; departureIdChange = -1; customerIdx = c; customerTurn = t; delta = newWeight - weight; } } } if (delta > 0) { if (departureIdChange != -1) { part[0] = DirectedHelper.SwitchDepartureOffset(part[0]); } else if (arrivalIdChange != -1) { part[part.Count - 1] = DirectedHelper.SwitchArrivalOffset(part[part.Count - 1]); } else if (customerIdx != -1) { part[customerIdx] = DirectedHelper.BuildDirectedId( DirectedHelper.ExtractId(part[customerIdx]), customerTurn); } } return(delta); }