/// <summary> /// Switches the given directed id to the best turn given the before and after directed id's. /// </summary> public static bool SwitchToBestTurn(int directedId, int beforeDirectedId, int afterDirectedId, float[][] weights, float[] turnPenalties, out int betterDirectedId, out bool departureIdSwitched, out bool arrivalIdSwitched, out float delta) { int arrivalId, departureId, turn, id, beforeDepartureOffset, afterArrivalOffset, temp; DirectedHelper.ExtractOffset(DirectedHelper.ExtractTurn(beforeDirectedId), out temp, out beforeDepartureOffset); DirectedHelper.ExtractOffset(DirectedHelper.ExtractTurn(afterDirectedId), out afterArrivalOffset, out temp); DirectedHelper.ExtractAll(directedId, out arrivalId, out departureId, out id, out turn); var bestWeight = float.MaxValue; var bestDirectedId = -1; var previousWeight = float.MaxValue; departureIdSwitched = false; arrivalIdSwitched = false; for (var newBeforeDepartureOffset = 0; newBeforeDepartureOffset < 2; newBeforeDepartureOffset++) { for (var newAfterArrivalOffset = 0; newAfterArrivalOffset < 2; newAfterArrivalOffset++) { for (var i = 0; i < 4; i++) { var newDirectedId = DirectedHelper.BuildDirectedId(id, i); int localTurn; DirectedHelper.ExtractAll(newDirectedId, out arrivalId, out departureId, out id, out localTurn); var newBeforeDirectedId = DirectedHelper.UpdateDepartureOffset(beforeDirectedId, newBeforeDepartureOffset); var newAfterDirectedId = DirectedHelper.UpdateArrivalOffset(afterDirectedId, newAfterArrivalOffset); var newBeforeDepartureId = DirectedHelper.ExtractDepartureId(newBeforeDirectedId); var newAfterArrivalId = DirectedHelper.ExtractArrivalId(newAfterDirectedId); var newBeforeTurn = DirectedHelper.ExtractTurn(newBeforeDirectedId); var newAfterTurn = DirectedHelper.ExtractTurn(newAfterDirectedId); var newWeight = turnPenalties[localTurn]; newWeight += weights[newBeforeDepartureId][arrivalId]; newWeight += weights[departureId][newAfterArrivalId]; newWeight += turnPenalties[newBeforeTurn]; newWeight += turnPenalties[newAfterTurn]; if (i == turn && newBeforeDepartureOffset == beforeDepartureOffset && newAfterArrivalOffset == afterArrivalOffset) { previousWeight = newWeight; } if (bestWeight > newWeight) { bestWeight = newWeight; bestDirectedId = newDirectedId; departureIdSwitched = newBeforeDepartureOffset != beforeDepartureOffset; arrivalIdSwitched = newAfterArrivalOffset != afterArrivalOffset; } } } } delta = previousWeight - bestWeight; betterDirectedId = bestDirectedId; return(betterDirectedId != directedId); }
/// <summary> /// Calculates the weights between the two directed id's without the turn weights. /// </summary> public static float WeightWithoutTurns(this float[][] weights, int directed1, int directed2) { int arrivalId1, departureId1, id1, turn1, arrivalId2, departureId2, id2, turn2; DirectedHelper.ExtractAll(directed1, out arrivalId1, out departureId1, out id1, out turn1); DirectedHelper.ExtractAll(directed2, out arrivalId2, out departureId2, out id2, out turn2); return(weights[departureId1][arrivalId2]); }
/// <summary> /// Calculates the weight of the given tour. /// </summary> public static float Weight(this Tour tour, float[][] weights, float[] turnPenalties) { var weight = 0f; var previousFrom = int.MaxValue; var firstTo = int.MaxValue; var lastTurn = int.MaxValue; foreach (var directedId in tour) { // extract turns and stuff from directed id. int arrivalId, departureId, id, turn; DirectedHelper.ExtractAll(directedId, out arrivalId, out departureId, out id, out turn); // add the weight from the previous customer to the current one. if (previousFrom != int.MaxValue) { weight = weight + weights[previousFrom][arrivalId]; } else { firstTo = arrivalId; } // add turn penalty. if ((tour.First != directedId && tour.Last != directedId) || tour.Last == tour.First) { // never count turn @ first customer. // don't count turn @ last customer if it's different from first. weight += turnPenalties[turn]; } previousFrom = departureId; lastTurn = turn; } // remove the last turn penalty if it's an open non-fixed tour. if (tour.Last == null) { weight -= turnPenalties[lastTurn]; } // add the weight between last and first. if (previousFrom != int.MaxValue && tour.First == tour.Last) { weight = weight + weights[previousFrom][firstTo]; } return(weight); }