private static void PrintFinalSolution(Solution solution) { double totalDist = 0; StreamWriter sw = new StreamWriter("d:\\temp\\out.txt", false); string finalPath = ""; foreach (Route route in solution.routes) { totalDist += route.totalDist; bool zeroCrossed = false; string part1 = ""; string part2 = ""; for (int i = 0; i < route.ids.Count; i++) { if (route.ids[i] == 0) { zeroCrossed = true; } else { if (zeroCrossed) { part2 += route.ids[i] + " "; } else { part1 += route.ids[i] + " "; } } } string path = "0 " + part2.Trim() + " " + part1.Trim() + " 0"; path = path.Replace(" ", " "); finalPath += path + "\r\n"; } sw.WriteLine((int)totalDist + " 0"); ////for (int i = 0; i < numTrucks - solution.routes.Count; i++) { //// finalPath += "0 0\r\n"; ////} sw.WriteLine(finalPath); sw.Close(); }
private static void PrintSolution(Solution solution) { double totalDist = 0; StreamWriter sw = new StreamWriter("d:\\temp\\vrp\\out\\" + problem + ".txt", false); foreach (Route route in solution.routes) { string thisPath = ""; int truckId = route.truckId; double thisDist = route.totalDist; totalDist += thisDist; int thisCap = truckCapacity - route.unusedDemand; foreach (int id in route.ids) { thisPath += id + " "; } string pathStr = String.Format("TruckId = {0} Dist = {1:N} DemandSatisfied = {2} :: Path = {3}", truckId, thisDist, thisCap, thisPath); Console.WriteLine(pathStr); sw.WriteLine(pathStr); } string totalDistStr = String.Format("Totaldist = {0:N}", totalDist); Console.WriteLine(totalDistStr); sw.WriteLine(totalDistStr); sw.Close(); }
//Take pairs of points (p1,p2) from 2 trucks and try to swap them if the capacity //constraints are satisfied. Now perform 2-opt on both the trucks and report new neighbour //if the cost is improved. private static Solution LS2(Solution basicSoln) { int currLs2Count = 0; Solution currBestSol = basicSoln; bool doMore = true; while (doMore && currLs2Count++ < LS2Count) { Console.Write("\n\tLS2 : Trial " + currLs2Count + " "); double costSavings = 0; int t1 = 0, t2 = 0; int nodei = 0, nodej = 0; Solution betterSol = LS2Step(currBestSol, ref costSavings, ref t1, ref t2, ref nodei, ref nodej, true); if (betterSol == null) { doMore = false; } else { currBestSol = betterSol; Console.Write(" : Move a point from {0} to {1} for cost savings = {2:N} :: Curr Total Cost = {3:N}", t1, t2, costSavings, GetSolutionCost(currBestSol)); } } return currBestSol; }
private static Solution LS2Step(Solution basicSoln, ref double costSavings, ref int trucki, ref int truckj, ref int nodei, ref int nodej, bool exploreAll) { Solution betterSol = new Solution(); costSavings = 0; bool foundBetter = false; /*try to swap nodes pi and pj between truck_i and truck_j if the capccity constraints are satisfied*/ Route iRoute, jRoute; for (int i = 0; i < numTrucks - 1; i++) { iRoute = basicSoln.routes[i]; int freeCapacityIni = iRoute.unusedDemand; for (int j = i + 1; j < numTrucks; j++) { jRoute = basicSoln.routes[j]; int freeCapacityInj = jRoute.unusedDemand; if (iRoute.ids.Count == 0 || jRoute.ids.Count == 0) continue; double origCost = iRoute.totalDist + jRoute.totalDist; for (int piIdx = 0; piIdx < iRoute.ids.Count; piIdx++) { int pi = iRoute.ids[piIdx]; if (pi == 0) continue; for (int pjIdx = 0; pjIdx < jRoute.ids.Count; pjIdx++) { int pj = jRoute.ids[pjIdx]; if (pj == 0) continue; int demi = demands[pi]; int demj = demands[pj]; if ((freeCapacityIni + demi - demj >= 0) && (freeCapacityInj + demj - demi >= 0)) { List<int> newiPath = new List<int>(iRoute.ids); newiPath.Remove(pi); newiPath.Add(pj); List<int> newjPath = new List<int>(jRoute.ids); newjPath.Remove(pj); newjPath.Add(pi); bool foundBetteri = false, foundBetterj = false; double newLeni = 0, newLenj = 0; int[] betteriRoute = TwoOpt(newiPath.ToArray(), ref foundBetteri, ref newLeni, false); int[] betterjRoute = TwoOpt(newjPath.ToArray(), ref foundBetterj, ref newLenj, false); double newCost = newLeni + newLenj; double thisCostSavings = origCost - newCost; if (thisCostSavings > 0.000001) { if (thisCostSavings > costSavings) { costSavings = thisCostSavings; trucki = i; truckj = j; nodei = pi; nodej = pj; foundBetter = true; Route newiRoute = new Route(); if (foundBetteri && betteriRoute != null) { newiRoute.ids = betteriRoute.ToList(); } else { newiRoute.ids = newiPath; } newiRoute.totalDist = newLeni; newiRoute.truckId = iRoute.truckId; newiRoute.unusedDemand = iRoute.unusedDemand + demi - demj; Route newjRoute = new Route(); if (foundBetterj && betterjRoute != null) { newjRoute.ids = betterjRoute.ToList(); } else { newjRoute.ids = newjPath; } newjRoute.totalDist = newLenj; newjRoute.truckId = jRoute.truckId; newjRoute.unusedDemand = jRoute.unusedDemand + demj - demi; betterSol = new Solution(); //create the new solution with modified i and j routes for (int t = 0; t < basicSoln.routes.Count; t++) { if (t == i) { betterSol.routes.Add(newiRoute); } else if (t == j) { betterSol.routes.Add(newjRoute); } else { betterSol.routes.Add(basicSoln.routes[t]); } } if (!exploreAll) { goto end; } } } } } } } } end: if (foundBetter) { return betterSol; } else { return null; } }
//Take p2 from route1 and add to route2 if the capacity constraints are satisfied in route2 //Then, via a sequence of 2-opt moves in route2 and route1, optimize both the routes. //if(new_dist_r2+new_dist_r1 < old_dist_r2_old_dist_r1), then we got a better neighbour private static Solution LS1(Solution basicSoln) { int currLs1Count = 0; Solution currBestSol = basicSoln; bool doMore = true; while (doMore && currLs1Count++ < LS1Count) { Console.Write("\n\tLS1 : Trial " + currLs1Count + " "); double costSavings = 0; int t1 = 0, t2 = 0; Solution betterSol = LS1Step(currBestSol, ref costSavings, ref t1, ref t2); if (betterSol == null) { doMore = false; } else { currBestSol = betterSol; Console.Write(" : Move a point from {0} to {1} for cost savings = {2:N}", t1, t2, costSavings); } } return currBestSol; }
//Perform 2-OPT optimization for all the routes in the basic solution //return the optimized solution if one is found. private static Solution LS0(Solution basicSoln) { Solution newSol = new Solution(); for (int i = 0; i < basicSoln.routes.Count; i++) { Route thisRoute = basicSoln.routes[i]; Console.WriteLine("\tLS 0 : Truck : " + thisRoute.truckId); int currCount = 0; bool doMore = true; Route bestRouteSoFarForThisTruck = thisRoute; while (doMore && currCount++ < LS0Count) { double costSavings = 0; Route newRoute = TwoOpt(bestRouteSoFarForThisTruck, ref costSavings); if (newRoute == null) { doMore = false; } else { bestRouteSoFarForThisTruck = newRoute; } } newSol.routes.Add(bestRouteSoFarForThisTruck); } return newSol; }
private static double GetSolutionCost(Solution solution) { double totalDist = 0; foreach (Route route in solution.routes) { totalDist += route.totalDist; } return totalDist; }
private static Solution GetInitialFeasibleSolution(NodeInfo[] nodes) { Solution soln = new Solution(); int currTruck = 1; bool allDemandSatisfied = false; HashSet<int> assignedNodes = new HashSet<int>(); while (!allDemandSatisfied && currTruck <= numTrucks) { int availableCap = truckCapacity; //iterate over each of the nodes and if any node has not been assigned yet //to any truck and the capacity constraints of the truck are satisfied, then //assign this node to this truck. Route thisRoute = new Route(); thisRoute.ids.Add(0); thisRoute.truckId = currTruck; thisRoute.unusedDemand = availableCap; for (int i = 0; i < nodes.Length; i++) { if (nodes[i].id != 0) { int thisNodeId = nodes[i].id; int thisNodeDemand = demands[thisNodeId]; if (!assignedNodes.Contains(thisNodeId) && availableCap >= thisNodeDemand) { availableCap -= thisNodeDemand; assignedNodes.Add(thisNodeId); thisRoute.ids.Add(thisNodeId); thisRoute.unusedDemand = availableCap; if (assignedNodes.Count == nodes.Length - 1) { allDemandSatisfied = true; break; } } } } //thisRoute.ids.Add(0); /*to keep it consistent with tsp routines*/ CalculateRouteDistance(thisRoute); soln.routes.Add(thisRoute); currTruck++; } if (!allDemandSatisfied) { return null; } else { //fill up additional trucks with path : 0-0 int usedTrucks = soln.routes.Count; for (int i = 0; i < numTrucks - usedTrucks; i++) { soln.routes.Add(new Route() { ids = new List<int>() {0}, totalDist = 0, unusedDemand = truckCapacity, truckId = currTruck++ }); } return soln; } }
private static Solution LS1Step(Solution basicSoln, ref double costSavings, ref int trucki, ref int truckj) { Solution betterSol = new Solution(); bool foundBetter = false; /*try to move a node from truck_i to truck_j if the capccity constraints are satisfied*/ Route iRoute, jRoute; for (int i = 0; i < numTrucks; i++) { iRoute = basicSoln.routes[i]; for (int j = 0; j < numTrucks; j++) { jRoute = basicSoln.routes[j]; int freeCapacityInj = jRoute.unusedDemand; if (i == j) continue; if (freeCapacityInj == 0) continue; if (iRoute.ids.Count == 0) continue; List<int> idsToProbe = iRoute.ids.Where(x => x != 0 && demands[x] <= freeCapacityInj).ToList(); for (int k = 0; k < idsToProbe.Count; k++) { if (idsToProbe[k] != 0) { /*we cannot move the origin from i to j*/ int demandOfThisPointIni = demands[idsToProbe[k]]; if (freeCapacityInj >= demandOfThisPointIni) { /*capccity constraints are satisfied*/ /*move ids[k] from truck_i to truck_j*/ List<int> newiPath = new List<int>(iRoute.ids); newiPath.Remove(idsToProbe[k]); ; List<int> newjPath = new List<int>(jRoute.ids); newjPath.Add(idsToProbe[k]); double origCost = iRoute.totalDist + jRoute.totalDist; bool foundBetteri = false, foundBetterj =false; double newLeni = 0, newLenj = 0; int[] betteriRoute = TwoOpt(newiPath.ToArray(), ref foundBetteri, ref newLeni, false); int[] betterjRoute = TwoOpt(newjPath.ToArray(), ref foundBetterj, ref newLenj, false); double newCost = newLeni + newLenj; costSavings = origCost-newCost; if (costSavings > 0.000001) { trucki = i; truckj = j; foundBetter = true; Route newiRoute = new Route(); if (foundBetteri && betteriRoute != null) { newiRoute.ids = betteriRoute.ToList(); } else { newiRoute.ids = iRoute.ids; } newiRoute.totalDist = newLeni; newiRoute.truckId = iRoute.truckId; newiRoute.unusedDemand = iRoute.unusedDemand + demandOfThisPointIni; Route newjRoute = new Route(); if (foundBetterj && betterjRoute != null) { newjRoute.ids = betterjRoute.ToList(); } else { newjRoute.ids = jRoute.ids; } newjRoute.totalDist = newLenj; newjRoute.truckId = jRoute.truckId; newjRoute.unusedDemand = jRoute.unusedDemand - demandOfThisPointIni; //create the new solution with modified i and j routes for (int t = 0; t < basicSoln.routes.Count; t++) { if (t == i) { betterSol.routes.Add(newiRoute); } else if (t == j) { betterSol.routes.Add(newjRoute); } else { betterSol.routes.Add(basicSoln.routes[t]); } } goto end; } } } } } } end: if (foundBetter) { return betterSol; } else { return null; } }