public bool DoubleShift(double ctrlPM, int sDay1, int sDay2, int sRoute1, int sRoute2, int orderIndex1, int orderIndex2, Order order) { Day startDay1 = week.GetWeek[sDay1], startDay2 = week.GetWeek[sDay2]; Route startRoute1 = startDay1.GetRoutes[sRoute1], startRoute2 = startDay2.GetRoutes[sRoute2]; //The target Days/Routes, to shift to Day tarDay1, tarDay2; Route tarRoute1, tarRoute2; double totalTimeChange1 = 0, totalTimeChange2 = 0; //mo 1; tu 2; we 3; thu 4; fr 5 //Tuesday if (startDay1.DayNumber == 2) { //Grab one of the two days conforming to the correct dayNumber tarDay1 = week.GetWeek[random.Next(0, 2)]; //To monday (0,1) tarDay2 = week.GetWeek[random.Next(6, 8)]; //To thursday (6,7) if (tarDay1.GetRoutes.Count == 0 || tarDay2.GetRoutes.Count == 0) { return(true); } //Grab a route randomly on the target days tarRoute1 = tarDay1.GetRoutes[random.Next(tarDay1.GetRoutes.Count)]; tarRoute2 = tarDay2.GetRoutes[random.Next(tarDay2.GetRoutes.Count)]; } else //startday1.DayNumber == 1 aka monday { //Grab one of the two days conforming to the correct dayNumber tarDay1 = week.GetWeek[random.Next(2, 4)]; //To tuesday (2,3) tarDay2 = week.GetWeek[random.Next(8, 10)]; //To friday (8,9) if (tarDay1.GetRoutes.Count == 0 || tarDay2.GetRoutes.Count == 0) { return(true); } //Grab a route randomly on the target days tarRoute1 = tarDay1.GetRoutes[random.Next(tarDay1.GetRoutes.Count)]; tarRoute2 = tarDay2.GetRoutes[random.Next(tarDay2.GetRoutes.Count)]; } int index1 = -1, index2 = -1; //We'll try to shift twice, once for each order. If both succeed, we will actually shift them in another part of the code for (int s = 0; s < 2; s++) { #region shiftstuff Day tarDay, startDay; Route tarRoute, startRoute; int startIndex; //We do two iterations, with different days/routes each time if (s == 0) { tarDay = tarDay1; startDay = startDay1; tarRoute = tarRoute1; startRoute = startRoute1; startIndex = orderIndex1; } else { tarDay = tarDay2; startDay = startDay2; tarRoute = tarRoute2; startRoute = startRoute2; startIndex = orderIndex2; } //Original time of target route; original time of target day (to be calculated); new time of rout (tbc); value of best improvement double oTime = tarRoute.TotalTime(), oDayTime = 0, nTime = 0, best = double.MaxValue; int bestPos = -1, totalLoad = tarRoute.TotalLoad(); //Calc total time of the target day foreach (Route r in tarDay.GetRoutes) { oDayTime += r.TotalTime(); } //Calculate the time difference of removing the route from the starting route double sTime, nSTime, timeDiff; sTime = startRoute.TotalTime(); startRoute.Remove(startIndex); nSTime = startRoute.TotalTime(); timeDiff = sTime - nSTime; //Go over the target route, figure out the best location to shift to for (int i = 0; i < tarRoute.GetRoute.Count; i++) { tarRoute.GetRoute.Insert(i, order); nTime = tarRoute.TotalTime(); //Check if it's valid (time and load wise) and whether it's better if (oDayTime + nTime - oTime < WORKINGDAY && totalLoad + order.numberOfContainers * order.volumeOfOneContainer < MAXLOAD && nTime < best) { bestPos = i; best = nTime; } tarRoute.Remove(i); } bool accept = false, improvement1 = false, improvement2 = false; if (bestPos != -1) { if (s == 0) { totalTimeChange1 = timeDiff - (best - oTime); } else { totalTimeChange2 = timeDiff - (best - oTime); } //Check wether it is a net gain in time or not //TimeDiff is positive, because this much time is gained from the removal //best - oTime, the increase in route time //The total thing should be increase in new route measured against decrease in the other if (timeDiff - (best - oTime) >= 0) { //In case of this occuring, the shift was a net gain (more went out of the old route then came into the new route) if (s == 0) { index1 = bestPos; } else { index2 = bestPos; } //We re-insert here because we don't know if the other shift will succeed. If that happens, we remove again (seemed a little bit cleaner this way) startRoute.GetRoute.Insert(startIndex, order); } else { //Does the operation get through the q-test? accept = AcceptOperation(ctrlPM, timeDiff - (best - oTime)); if (accept) { //We accepted a loss if (s == 0) { index1 = bestPos; } else { index2 = bestPos; } //We re-insert here because we don't know if the other shift will succeed. If that happens, we remove again (seemed a little bit cleaner this way) startRoute.GetRoute.Insert(startIndex, order); } else { //No shift occured, re-insert the order to its original spot startRoute.GetRoute.Insert(startIndex, order); //startDay.UpdateRoutes(); return(true); } } } else { //No shift occured, re-insert the order to its original spot startRoute.GetRoute.Insert(startIndex, order); return(true); } #endregion } //if both iterations succeed, we do stuff! if (index1 != -1 && index2 != -1) { //Don't forget to change the bits! Also for freq 4 in the normal shift!!! //Remove and Add (shift) the orders startRoute1.Remove(orderIndex1); startRoute2.Remove(orderIndex2); tarRoute1.GetRoute.Insert(index1, order); tarRoute2.GetRoute.Insert(index2, order); //Change bits so future checks get the correct info order.SetBit(startDay1.DayNumber, false); order.SetBit(startDay2.DayNumber, false); order.SetBit(tarDay1.DayNumber, true); order.SetBit(tarDay2.DayNumber, true); //Update the now changed routes startDay1.UpdateRoutes(); startDay2.UpdateRoutes(); tarDay1.UpdateRoutes(); tarDay2.UpdateRoutes(); //Make sure to return whether this is a net gain or not return(totalTimeChange1 + totalTimeChange2 > 0); } return(true); }
public bool Shift(double ctrlPM) { int rndStartIndex; Tuple <int, int> rndStart, rndTarget; rndStart = SelectRandomRoute(); rndTarget = SelectRandomRoute(); //Get a random start and target route. Day tarDay = week.GetWeek[rndTarget.Item1]; Day startDay = week.GetWeek[rndStart.Item1]; Route startRoute = startDay.GetRoutes[rndStart.Item2]; Route tarRoute = tarDay.GetRoutes[rndTarget.Item2]; if (tarRoute.GetRoute.Count == 0 || startRoute.GetRoute.Count == 0) { return(true); } //Choose a random order from the startroute rndStartIndex = random.Next(startRoute.GetRoute.Count); Order order = startRoute.GetRoute[rndStartIndex]; if (order.frequency > 1) { if (tarDay.DayNumber != startDay.DayNumber) { if (order.frequency == 4) { return(true); //An order with frequency 4 should not be swapped to another day that has the order if (order.GetBit(tarDay.DayNumber)) { return(true); } } else if (order.frequency == 2) { #region freq2 int sDay1, sDay2, sRoute1, sRoute2, index1, index2, unprocessedDay = 0, processedDay = 0; Tuple <int, int, int> indices; //This gets which day, of mon and tue, is processed and unprocessed (from this we can glean the other day) for (int i = 1; i < 3; i++) { if (!order.GetBit(i)) { unprocessedDay = i; } else { processedDay = i; } } //startday can be mon, tue, thur, fri //can be in the first or latter part of the week //then, it can be bigger or smaller than the unprocessedDay if (startDay.DayNumber > 2) { if (startDay.DayNumber - 3 > unprocessedDay) //unprocessed is mon (startday is friday: 5 - 3 = 2; 2 > 1) { //other call should shift tue to mon, need to find out which truck does the order indices = FindOccurence(2, order); //this method finds out which day exactly contains the order //In this case, we have to obtain the truck that does the order on tuesday, we know of the truck on friday } else //Startday is thursday, unprocessed is tuesday { //other call should shift mon to tue, need to find out which truck does the order indices = FindOccurence(1, order); //this method finds out which day exactly contains the order } //Set the parameters, start day is in the latter half of the week. That means we had to use FindOccurence to find the earlier weekday, hence the indices use sDay1 = indices.Item1; sDay2 = rndStart.Item1; sRoute1 = indices.Item2; sRoute2 = rndStart.Item2; index1 = indices.Item3; index2 = rndStartIndex; } else //startDay is in the first half of the week { if (startDay.DayNumber > unprocessedDay) //Starting day is tuesday, unprocessed is monday { indices = FindOccurence(5, order); //Find the day in the latter half of the week (on friday) } else { indices = FindOccurence(4, order); } //Set the parameters, start day is in the latter half of the week. Note how indices is now used for the different day! sDay1 = rndStart.Item1; sDay2 = indices.Item1; sRoute1 = rndStart.Item2; sRoute2 = indices.Item2; index1 = rndStartIndex; index2 = indices.Item3; } if (indices.Item1 == -1 || indices.Item2 == -1 || indices.Item3 == -1) { return(true); } return(DoubleShift(ctrlPM, sDay1, sDay2, sRoute1, sRoute2, index1, index2, order)); #endregion } else { return(true); } } //All orders should be allowed to be swapped to the same day } #region shiftBody //Original time of target route; original time of target day (to be calculated); new time of rout (tbc); value of best improvement double oTime = tarRoute.TotalTime(), oDayTime = 0, nTime = 0, best = double.MaxValue; int bestPos = -1, totalLoad = tarRoute.TotalLoad(); //Calc total time of the target day foreach (Route r in tarDay.GetRoutes) { oDayTime += r.TotalTime(); } //Calculate the time difference of removing the route from the starting route double sTime, nSTime, timeDiff; sTime = startRoute.TotalTime(); startRoute.Remove(rndStartIndex); nSTime = startRoute.TotalTime(); timeDiff = sTime - nSTime; //Go over the target route, figure out the best location to shift to for (int i = 0; i < tarRoute.GetRoute.Count; i++) { tarRoute.GetRoute.Insert(i, order); nTime = tarRoute.TotalTime(); //Check if it's valid (time and load wise) and whether it's better if (oDayTime + nTime - oTime < WORKINGDAY && totalLoad + order.numberOfContainers * order.volumeOfOneContainer < MAXLOAD && nTime < best) { bestPos = i; best = nTime; } tarRoute.Remove(i); } #endregion bool accept = false; if (bestPos != -1) { //Check wether it is a net gain in time or not //TimeDiff is positive, because this much time is gained from the removal //best - oTime, the increase in route time //The total thing should be increase in new route measured against decrease in the other if (timeDiff - (best - oTime) > 0) { //In case of this occuring, the shift was a net gain (more went out of the old route then came into the new route) tarRoute.GetRoute.Insert(bestPos, order); //Update Routes tarDay.UpdateRoutes(); startDay.UpdateRoutes(); //Change some bits if necessary if (order.frequency == 4 && startDay.DayNumber != tarDay.DayNumber) { order.SetBit(startDay.DayNumber, false); order.SetBit(tarDay.DayNumber, true); } return(true); } else //Order is not an improvement { accept = AcceptOperation(ctrlPM, timeDiff - (best - oTime)); if (accept) { //We accepted a deterioration tarRoute.GetRoute.Insert(bestPos, order); //Update Routes tarDay.UpdateRoutes(); startDay.UpdateRoutes(); bShifts++; //Change some bits if necessary if (order.frequency == 4 && startDay.DayNumber != tarDay.DayNumber) { order.SetBit(startDay.DayNumber, false); order.SetBit(tarDay.DayNumber, true); } return(false); } else { //Put the order back in its original spot when we fail to shift startRoute.GetRoute.Insert(rndStartIndex, order); return(true); } } } else { //Put the order back in its original spot when we fail to shift startRoute.GetRoute.Insert(rndStartIndex, order); return(true); } }