// Check demand attended by vehicles is correct respect the capacity - FOR DEBUG public static void checkDemand(CluVRPInstance instance, List <int>[] clusterRouteForVehicule, int[] vehicleRemSpace) { // Vehicle remmaining capacity is correct respect to cluster demand int[] clusterDemand = instance.clusters_demand; int totalDemand = 0; // Sum the total demand for vehicle for (int vehicle = 0; vehicle < clusterRouteForVehicule.Length; vehicle++) { int totalDemandOnVehicle = 0; for (int clusterIt = 0; clusterIt < clusterRouteForVehicule[vehicle].Count; clusterIt++) { int cluster = clusterRouteForVehicule[vehicle][clusterIt]; totalDemandOnVehicle += clusterDemand[cluster]; } // Sum the total demand of all vehicles totalDemand += totalDemandOnVehicle; // Asserts Debug.Assert(instance.capacity - totalDemandOnVehicle < 0); Debug.Assert(instance.capacity - totalDemandOnVehicle != vehicleRemSpace[vehicle] || vehicleRemSpace[vehicle] < 0); } // Assert Debug.Assert(totalDemand == clusterDemand.Sum()); }
/* * * Constructor * */ public CustomerStrongGRASP(CluVRPInstance instance, CluVRPSolution solution, Parameters parameters) { // Set variables this.instance = instance; this.solution = solution; this.parameters = parameters; // For local search execute order if (parameters.Customer_LS_Order.Length == 0) { this.localSearchsOrder = new List <LocalSearch> { LocalSearch.TwoOpt, LocalSearch.Relocate, LocalSearch.Exchange, LocalSearch.SwapCustomers }; } else { this.localSearchsOrder = new List <LocalSearch>(); for (int i = 0; i < parameters.Customer_LS_Order.Length; i++) { localSearchsOrder.Add((LocalSearch)parameters.Customer_LS_Order[i]); } } // End of constructor }
// Customer solution verification public void verifyCustomerSolution(CluVRPInstance instance) { // Verify number of vehicles int numberOfVehicles; if (instance.instance_type != Instance.GoldenIzquierdo) { numberOfVehicles = instance.vehicles; Debug.Assert(customersPaths.Length == numberOfVehicles, "The number of vehicles on the customer path is incorrect"); Debug.Assert(vehiculeRouteDistance.Length == numberOfVehicles, "The number of vehicles on the route distance is incorrect"); } else { numberOfVehicles = customersPaths.Length; } // Verify number of clusters int numberOfClusters = instance.clusters.Length; int clustersCounter = 0; for (int i = 0; i < customersPaths.Length; i++) { clustersCounter += customersPaths[i].Length; } Debug.Assert(numberOfClusters == clustersCounter - (customersPaths.Length * 2) + 1, "The number of cluster in the complete travel is incorrect"); // Verify number of customers int numberOfCustomers = instance.dimension; int customersCounter = 0; for (int i = 0; i < customersPaths.Length; i++) { for (int j = 0; j < customersPaths[i].Length; j++) { customersCounter += customersPaths[i][j].Count; } } Debug.Assert(numberOfCustomers == customersCounter - (numberOfVehicles * 2) + 1); // All clusters are correct List <int>[] vehicleRoute = clusterRouteForVehicule; for (int vehicle = 0; vehicle < vehicleRoute.Length; vehicle++) { List <int> clusterList = vehicleRoute[vehicle]; for (int clusterIt = 0; clusterIt < clusterList.Count; clusterIt++) { int clusterNumber = clusterList[clusterIt]; List <int> cluster = customersPaths[vehicle][clusterIt].ToList <int>(); List <int> clusterInstance = instance.clusters[clusterNumber].ToList <int>(); bool containsAll = Functions.ContainsAllItems(cluster, clusterInstance); if (vehicleRoute[vehicle].Count != 2) { Debug.Assert(containsAll && cluster.Count == clusterInstance.Count, "All the clusters on the travel are not correct respect to their clients"); } } } // Total distance is correct Debug.Assert(Math.Truncate(totalCustomerRouteDistance) == Math.Truncate(Functions.calculateTotalTravelDistance(customersPaths, instance.customersDistanceMatrix, instance)), "The final distance is not correct"); }
// New LS to final solutions public static void cluVRPLocalSearchs(CluVRPSolution cluVRPSolution, CluVRPInstance instance, Parameters parameters) { // Perform LS at cluster level double oldTotalDistance = cluVRPSolution.totalCustomerRouteDistance; var totalWatch = System.Diagnostics.Stopwatch.StartNew(); swapClusters(cluVRPSolution, instance, parameters); cluVRPSolution.cluvrp_swapClusters_time += totalWatch.ElapsedMilliseconds; totalWatch = System.Diagnostics.Stopwatch.StartNew(); swapVehicle(cluVRPSolution, instance, parameters); cluVRPSolution.cluvrp_swapVehicle_time += totalWatch.ElapsedMilliseconds; // If some cluster position change make LS at customer level if (cluVRPSolution.totalCustomerRouteDistance < oldTotalDistance) { // Create a local search handler for cluster-level problem CustomerStrongLocalSearch customerLocalSearch = new CustomerStrongLocalSearch(cluVRPSolution, instance, parameters.Customer_LS_TwoOpt_Iterations, parameters.Customer_LS_Relocate_Iterations, parameters.Customer_LS_Exchange_Iterations, parameters.Customer_LS_SwapCustomers ); // Perform one iteration of LS at customer level customerLocalSearch.twoOpt(); customerLocalSearch.exchange(); customerLocalSearch.relocate(); customerLocalSearch.swapCustomers(); } // End return; }
// Cluster solution verification public void verifyClusterSolution(CluVRPInstance instance) { // All cluster was visited bool wasVisited = false; for (int cluster = 0; cluster < instance.clusters.Length; cluster++) { for (int vehicle = 0; vehicle < clusterRouteForVehicule.Length; vehicle++) { if (clusterRouteForVehicule[vehicle].Contains(cluster)) { wasVisited = true; break; } } Debug.Assert(wasVisited, "All clusters are not visited"); wasVisited = false; } // Number of clusters visited is correct int totalLength = 0; for (int vehicle = 0; vehicle < clusterRouteForVehicule.Length; vehicle++) { totalLength += clusterRouteForVehicule[vehicle].Count; } Debug.Assert(instance.clusters.Length == totalLength - (2 * clusterRouteForVehicule.Length) + 1, "Number of cluster visited is incorrect"); // Vehicle remmaining capacity is correct respect to cluster demand int[] clusterDemand = instance.clusters_demand; int totalDemand = 0; // Sum the total demand for vehicle for (int vehicle = 0; vehicle < clusterRouteForVehicule.Length; vehicle++) { int totalDemandOnVehicle = 0; for (int clusterIt = 0; clusterIt < clusterRouteForVehicule[vehicle].Count; clusterIt++) { int cluster = clusterRouteForVehicule[vehicle][clusterIt]; totalDemandOnVehicle += clusterDemand[cluster]; } // Sum the total demand of all vehicles totalDemand += totalDemandOnVehicle; Debug.Assert(instance.capacity - totalDemandOnVehicle >= 0, "The total demand is more big than the capacity of a vehicle"); } Debug.Assert(totalDemand == clusterDemand.Sum(), "The total demand is more big than the total capacity"); // Verify if all vehicules visit at least 1 cluster // This is necessary for GVRP and GoldelBattarra instances if (instance.instance_type == Instance.GVRP || instance.instance_type == Instance.GoldenBattarra) { for (int vehicle = 0; vehicle < clusterRouteForVehicule.Length; vehicle++) { Debug.Assert(clusterRouteForVehicule[vehicle].Count > 2, "There are vehicles that no visit clusters"); } } }
/* * * Read every instance file of InstanceSetName file and create a instance of it * */ static public CluVRPInstance[] loadGVRPSetOfInstances(string InstanceSetName) { // Init variables string filePath = InstanceSetName; CluVRPInstance[] gvrpInstances; // Main Cycle try { string[] lines = System.IO.File.ReadAllLines(filePath); gvrpInstances = new CluVRPInstance[lines.Length]; // Get all the instances setted on the file int i = 0; foreach (string instanceFilePath in lines) { // Try to parse instance try { CluVRPInstance instance; string[] instanceFileText = System.IO.File.ReadAllLines(instanceFilePath); if (instanceFilePath.Contains("rho")) { instance = parseGoldenIzquierdoInstance(instanceFilePath, instanceFileText); } else if (instanceFilePath.Contains("Golden")) { instance = parseGoldenBattarraInstance(instanceFilePath, instanceFileText); } else { instance = parseGVRPInstance(instanceFilePath, instanceFileText); } gvrpInstances[i] = instance; i++; } catch (Exception e) { Logger.GetInstance().logLine(e.ToString()); } } }catch (Exception e) { Logger.GetInstance().logLine(e.ToString()); return(null); } // Return array of instances return(gvrpInstances); }
// Constructor public CustomerStrongLocalSearch(CluVRPSolution solution, CluVRPInstance instance, int maxIterationsWithoutImprovementTwoOpt = 100, int maxIterationsWithoutImprovementRelocate = 100, int maxIterationsWithoutImprovementExchange = 100, int maxIterationsWithoutImprovementSwapCustomers = 100) { this.solution = solution; this.instance = instance; this.maxIterationsWithoutImprovementTwoOpt = maxIterationsWithoutImprovementTwoOpt; this.maxIterationsWithoutImprovementRelocate = maxIterationsWithoutImprovementRelocate; this.maxIterationsWithoutImprovementExchange = maxIterationsWithoutImprovementExchange; this.maxIterationsWithoutImprovementSwapCustomers = maxIterationsWithoutImprovementSwapCustomers; }
// Customer solution verification public void verifyCustomerWeakSolution(CluVRPInstance instance) { // Verify number of vehicles int numberOfVehicles; if (instance.instance_type != Instance.GoldenIzquierdo) { numberOfVehicles = instance.vehicles; } else { numberOfVehicles = customersWeakRoute.Length; } Debug.Assert(customersWeakRoute.Length == numberOfVehicles, "CustomerWeak - The number of vehicles is incorrect respect to customer path"); Debug.Assert(vehiculeRouteDistance.Length == numberOfVehicles, "CustomerWeak - The number of vehicles is incorrect respect to vehicles distance vector"); // Verify number of customers and all paths start and end on depot int numberOfCustomers = instance.dimension; int customersCounter = 0; for (int i = 0; i < customersWeakRoute.Length; i++) { customersCounter += customersWeakRoute[i].Count; Debug.Assert(customersWeakRoute[i][0] == 1 && customersWeakRoute[i][customersWeakRoute[i].Count - 1] == 1, "CustomerWeak - There is a customer path that not start or end on the depot"); } Debug.Assert(numberOfCustomers == customersCounter - (numberOfVehicles * 2) + 1, "CustomerWeak - The number of total customers is incorrect on the travel"); // All clusters are correct List <int>[] vehicleRoute = clusterRouteForVehicule; for (int vehicle = 0; vehicle < vehicleRoute.Length; vehicle++) { List <int> clusterList = vehicleRoute[vehicle]; int allClustersSizeSum = 0; for (int clusterIt = 0; clusterIt < clusterList.Count; clusterIt++) { int clusterNumber = clusterList[clusterIt]; List <int> cluster = customersWeakRoute[vehicle].ToList <int>(); List <int> clusterInstance = instance.clusters[clusterNumber].ToList <int>(); allClustersSizeSum += clusterInstance.Count; bool containsAll = Functions.ContainsAllItems(cluster, clusterInstance); Debug.Assert(containsAll, "CustomerWeak - All the clusters not contains the corrects customers"); } Debug.Assert(customersWeakRoute[vehicle].Count == allClustersSizeSum, "The total sum of customers is not correct on the travel"); } // Total distance is correct Debug.Assert(Math.Truncate(totalCustomerRouteDistance) == Math.Truncate(Functions.calculateCustomerTotalTravelDistanceForVehicle(customersWeakRoute, instance.customersDistanceMatrix, instance)), "CustomerWeak - The final distance is not correct"); }
// Constructor public ClusterLocalSearch(CluVRPSolution solution, CluVRPInstance instance, int maxIterationsWithoutImprovementTwoOpt = 100, int maxIterationsWithoutImprovementRelocate = 100, int maxIterationsWithoutImprovementExchange = 100, //int maxIterationsWithoutImprovementIVRS = 100, //int maxIterationsWithoutImprovementIVRC = 100, int maxIterationsWithoutImprovementIV = 100, int maxIterationsWithoutImprovementSV = 100, int maxIterationsWithoutImprovementSC = 100 ) { this.solution = solution; this.instance = instance; this.maxIterationsWithoutImprovementTwoOpt = maxIterationsWithoutImprovementTwoOpt; this.maxIterationsWithoutImprovementRelocate = maxIterationsWithoutImprovementRelocate; this.maxIterationsWithoutImprovementExchange = maxIterationsWithoutImprovementExchange; //this.maxIterationsWithoutImprovementIVRS = maxIterationsWithoutImprovementIVRS; //this.maxIterationsWithoutImprovementIVRC = maxIterationsWithoutImprovementIVRC; this.maxIterationsWithoutImprovementIV = maxIterationsWithoutImprovementIV; this.maxIterationsWithoutImprovementSV = maxIterationsWithoutImprovementSV; this.maxIterationsWithoutImprovementSC = maxIterationsWithoutImprovementSC; }
// Calculate the total customer distance of a all vehicles public static double calculateCustomerTotalTravelDistanceForVehicle(List <int>[] travel, double[][] customersDistanceMatrix, CluVRPInstance instance) { // Set variables double totalDistance = 0; for (int vehicle = 0; vehicle < travel.Length; vehicle++) { if (instance.instance_type == Instance.GoldenBattarra || instance.instance_type == Instance.GVRP) { totalDistance += (int)calculateCustomerTravelDistance(travel[vehicle], customersDistanceMatrix); } if (instance.instance_type == Instance.GoldenIzquierdo) { totalDistance += calculateCustomerTravelDistance(travel[vehicle], customersDistanceMatrix); } } // Return total distance return(totalDistance); }
// Calculate the total travel (visiting all the custer and customers by each vehicle) static public double calculateTotalTravelDistance(List <int>[][] customersCircuit, double[][] customersDistanceMatrix, CluVRPInstance instance) { double distance = 0; for (int vehicle = 0; vehicle < customersCircuit.Length; vehicle++) { if (instance.instance_type == Instance.GoldenBattarra || instance.instance_type == Instance.GVRP) { distance += (int)calculateTotalTravelDistance(customersCircuit, customersDistanceMatrix, vehicle); } if (instance.instance_type == Instance.GoldenIzquierdo) { distance += calculateTotalTravelDistance(customersCircuit, customersDistanceMatrix, vehicle); } } return(distance); }
// Write a python script to draw the solution public static void solutionDrawPythonCode(CluVRPInstance instance, CluVRPSolution solution) { // Lines of file List <string> lines = new List <string>(); // Add initial lines to script lines.Add("import matplotlib.pyplot as plt"); lines.Add("plt.figure(num=None, figsize=(24, 16), dpi=120, facecolor='w', edgecolor='k')"); // For python vars string[] abc = new string[] { "a", "b", "c", "d", "f", "g", "h", "i", "j", "k", "l", "m", "k", "r", "t", "u", "v", "w", "y", "z", "aa", "ab", "ac", "ad", "af", "ag", "ah", "ai", "aj", "ak", "al", "am", "ak", "ar", "at", "au", "av", "aw", "ay", "az", "ca", "cb", "cc", "cd", "cf", "cg", "ch", "ci", "cj", "ck", "cl", "cm", "ck", "cr", "ct", "cu", "cv", "cw", "cy", "cz" }; // Array of colors string[] colors = new string[] { "aqua", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "green", "greenyellow", "grey", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen" }; string[] vehicle_colors = new string[] { "red", "green", "blue", "orange", "purple", "cyan", "magenta", "lime", "pink", "teal", "lavender", "brown", "beige", "maroon", "mint", "olive", "coral", "navy", "grey", "white", "black" }; // Variables int colorIt = 0; int var1 = 0; int var2 = 1; string outFileName = instance.file_name + ".py"; // Code for draw the customers points // All customers of one cluster have the same color string array1 = abc[var1] + "= [" + instance.nodes[0].x.ToString().Replace(',', '.') + "]"; string array2 = abc[var2] + "= [" + instance.nodes[0].y.ToString().Replace(',', '.') + "]"; string array3 = "plt.plot(" + abc[0] + "," + abc[1] + ",'ro', markersize= 44, color = '" + colors[0] + "')"; lines.Add(array1); lines.Add(array2); lines.Add(array3); var1 = var1 + 2; var2 = var2 + 2; colorIt++; for (int clusterIt = 1; clusterIt < instance.clusters.Length; clusterIt++) { array1 = abc[var1] + "= ["; array2 = abc[var2] + "= ["; for (int customerIt = 0; customerIt < instance.clusters[clusterIt].Length; customerIt++) { int customer = instance.clusters[clusterIt][customerIt] - 1; array1 += instance.nodes[customer].x.ToString().Replace(',', '.') + ","; array2 += instance.nodes[customer].y.ToString().Replace(',', '.') + ","; } StringBuilder sb = new StringBuilder(array1); sb[sb.Length - 1] = ']'; array1 = sb.ToString(); sb = new StringBuilder(array2); sb[sb.Length - 1] = ']'; array2 = sb.ToString(); array3 = "plt.plot(" + abc[var1] + "," + abc[var2] + ",'ro', color = '" + colors[colorIt] + "')"; // For centroides var1 = (var1 + 2) % abc.Length; var2 = (var1 + 2) % abc.Length; string array4 = abc[var1] + "= ["; string array5 = abc[var2] + "= ["; array4 += instance.clustersCentroid[clusterIt].Item1.ToString().Replace(',', '.') + "]"; array5 += instance.clustersCentroid[clusterIt].Item2.ToString().Replace(',', '.') + "]"; string array6 = "plt.plot(" + abc[var1] + "," + abc[var2] + ",'ro',markersize=22, color = '" + colors[colorIt] + "')"; // Write python code for clusters and customers lines.Add(array1); lines.Add(array2); lines.Add(array3); lines.Add(array4); lines.Add(array5); lines.Add(array6); // Change color and variables name for next cluster var1 = (var1 + 2) % abc.Length; var2 = (var2 + 2) % abc.Length; colorIt = (colorIt + 1) % colors.Length; } // Draw vehicle travel var1 = 0; var2 = 1; colorIt = 0; for (int vehicle = 0; vehicle < solution.customersPaths.Length; vehicle++) { array1 = abc[var1] + "= ["; array2 = abc[var2] + "= ["; for (int clusterIt = 0; clusterIt < solution.customersPaths[vehicle].Length; clusterIt++) { for (int customerIt = 0; customerIt < solution.customersPaths[vehicle][clusterIt].Count; customerIt++) { int customer = solution.customersPaths[vehicle][clusterIt][customerIt] - 1; array1 += instance.nodes[customer].x.ToString().Replace(',', '.') + ","; array2 += instance.nodes[customer].y.ToString().Replace(',', '.') + ","; } } StringBuilder sb = new StringBuilder(array1); sb[sb.Length - 1] = ']'; array1 = sb.ToString(); sb = new StringBuilder(array2); sb[sb.Length - 1] = ']'; array2 = sb.ToString(); array3 = "plt.plot(" + abc[var1] + "," + abc[var2] + ", color = '" + vehicle_colors[colorIt] + "')"; // Write python code for clusters and customers lines.Add(array1); lines.Add(array2); lines.Add(array3); // Change color and variables name for next cluster var1 = (var1 + 2) % abc.Length; var2 = (var2 + 2) % abc.Length; colorIt = (colorIt + 1) % vehicle_colors.Length; } // Add final line lines.Add("plt.savefig('" + instance.file_name + ".png')"); // Write file try { System.IO.File.WriteAllLines(outFileName, lines); } catch (Exception e) { Console.WriteLine(e.ToString()); } // Excute script System.Diagnostics.Process.Start(PYTHON_PATH, outFileName); }
// Constructor public CluVRPSolution(CluVRPInstance instance) { totalClusterRouteDistance = double.MaxValue; instaceType = instance.instance_type; }
// Try to swap all the clusters (one bye one) for all vehicles (one by one) public static void swapVehicle(CluVRPSolution solution, CluVRPInstance instance, Parameters parameters) { // Cluster demand int[] clusterDemand = instance.clusters_demand; // More than 1 vehicle is needed if (solution.clusterRouteForVehicule.Length < 2) { return; } // Main cycle int iterations = 0; while (iterations < parameters.CluVRP_LS_SwapVehicle) { // For random order on iterations List <int> rndPosition = new List <int>(); for (int i = 0; i < solution.clusterRouteForVehicule.Length; i++) { rndPosition.Add(i); } Functions.Shuffle <int>(new Random(), rndPosition); // For each vehicle 1 for (int vehicleIt1 = 0; vehicleIt1 < solution.clusterRouteForVehicule.Length; vehicleIt1++) { // For each vehicle 2 for (int vehicleIt2 = 0; vehicleIt2 < solution.clusterRouteForVehicule.Length; vehicleIt2++) { // When is not the same vehicle if (vehicleIt1 != vehicleIt2) { // Select vehicle index from random position int vehicle1 = rndPosition[vehicleIt1]; int vehicle2 = rndPosition[vehicleIt2]; // For each cluster 1 on vehicle 1 for (int cluster1 = 1; cluster1 < solution.clusterRouteForVehicule[vehicle1].Count; cluster1++) { // For each cluster 2 on vehicle 2 for (int cluster2 = 1; cluster2 < solution.clusterRouteForVehicule[vehicle2].Count; cluster2++) { // Calculate the space on vehicle if make a swap int clusterSwappedV1 = solution.clusterRouteForVehicule[vehicle1][cluster1]; int clusterSwappedV2 = solution.clusterRouteForVehicule[vehicle2][cluster2]; int newSpaceV1 = solution.vehicleRemSpace[vehicle1] + clusterDemand[clusterSwappedV1] - clusterDemand[clusterSwappedV2]; int newSpaceV2 = solution.vehicleRemSpace[vehicle2] + clusterDemand[clusterSwappedV2] - clusterDemand[clusterSwappedV1]; // If swap is possible if (newSpaceV1 > 0 && newSpaceV2 > 0 && clusterSwappedV1 != 0 && clusterSwappedV2 != 0 && clusterSwappedV1 != clusterSwappedV2) { int lastClusterSwappedV1 = solution.clusterRouteForVehicule[vehicle1][cluster1 - 1]; int lastClusterSwappedV2 = solution.clusterRouteForVehicule[vehicle2][cluster2 - 1]; int nextClusterSwappedV1 = solution.clusterRouteForVehicule[vehicle1][cluster1 + 1]; int nextClusterSwappedV2 = solution.clusterRouteForVehicule[vehicle2][cluster2 + 1]; // Calculate old distances for each vehicle double oldDistanceVehicle1 = Functions.calculateCustomerTotalTravelDistanceForVehicle(solution.customersPaths[vehicle1], instance.customersDistanceMatrix, instance); double oldDistanceVehicle2 = Functions.calculateCustomerTotalTravelDistanceForVehicle(solution.customersPaths[vehicle2], instance.customersDistanceMatrix, instance); // Swap clusters List <int> cluster1Swp = solution.customersPaths[vehicle1][cluster1]; List <int> cluster2Swp = solution.customersPaths[vehicle2][cluster2]; solution.customersPaths[vehicle1][cluster1] = cluster2Swp; solution.customersPaths[vehicle2][cluster2] = cluster1Swp; // Calculate new distances for each vehicle double newDistanceVehicle1 = Functions.calculateCustomerTotalTravelDistanceForVehicle(solution.customersPaths[vehicle1], instance.customersDistanceMatrix, instance); double newDistanceVehicle2 = Functions.calculateCustomerTotalTravelDistanceForVehicle(solution.customersPaths[vehicle2], instance.customersDistanceMatrix, instance); // Calculate new total distance double newDistance = solution.totalClusterRouteDistance - (oldDistanceVehicle1 + oldDistanceVehicle2) + (newDistanceVehicle1 + newDistanceVehicle2); // If new distance is short if (newDistance + 0.0001 < solution.totalClusterRouteDistance) { // Update distance and space remaining solution.totalClusterRouteDistance = newDistance; solution.vehicleRemSpace[vehicle1] = newSpaceV1; solution.vehicleRemSpace[vehicle2] = newSpaceV2; solution.clusterRouteForVehicule[vehicle1][cluster1] = clusterSwappedV2; solution.clusterRouteForVehicule[vehicle2][cluster1] = clusterSwappedV1; // Reset iterator if (solution.cluvrp_swapVehicle_iterations <= iterations) { solution.cluster_insertVehicle_iterations = iterations; } iterations = 0; // DEBUG Logger.GetInstance().logLine("DEBUG - Improve on swapVehicle"); } // If new distance is not short else { // Undo swap solution.customersPaths[vehicle1][cluster1] = cluster1Swp; solution.customersPaths[vehicle2][cluster2] = cluster2Swp; // Increase iterator iterations++; } } else { iterations++; } // End if swap is possible } // End for cluster 2 } // End for cluster 1 } // End if is not the same vehicle } // End for vehicle 2 } // End for vehicle 1 } //End return; }
// Main GRASP handle main iteration depending if use Complete version or TwoPhase public static CluVRPSolution Grasp(CluVRPInstance instance, Parameters parameters) { // For best solution CluVRPSolution bestSolution = new CluVRPSolution(instance); // Main cycle int iterator = 0; while (iterator < parameters.CluVRP_GRASPIterations) { // New Grasp for Cluster level instance ClusterGRASP clusterGrasp = new ClusterGRASP(instance, parameters); // Execute Grasp procedure var totalWatch = System.Diagnostics.Stopwatch.StartNew(); CluVRPSolution cluVRPSolution = clusterGrasp.Grasp(); cluVRPSolution.clusterLevelTime = totalWatch.ElapsedMilliseconds; // If solutions is not available continue with next iteration if (cluVRPSolution.clusterRouteForVehicule == null) { iterator++; continue; } // Verify if cluster solution is correct cluVRPSolution.verifyClusterSolution(instance); // New Grasp for Cluster level instance CustomerLevel customerGrasp = null; if (parameters.CluVRP_Version == CluVRPVersion.Strong) { customerGrasp = new CustomerStrongGRASP(instance, cluVRPSolution, parameters); } else if (parameters.CluVRP_Version == CluVRPVersion.Weak) { customerGrasp = new CustomerWeakGRASP(instance, cluVRPSolution, parameters); } // Execute Grasp procedure totalWatch = System.Diagnostics.Stopwatch.StartNew(); customerGrasp.Grasp(); cluVRPSolution.customerLevelTime = totalWatch.ElapsedMilliseconds; //if solution is not available continue with next iteration if (cluVRPSolution.customersPaths == null && cluVRPSolution.customersWeakRoute == null) { continue; } // Perform LS if ((parameters.CluVRP_LS_SwapClusters > 0 || parameters.CluVRP_LS_SwapVehicle > 0) && parameters.CluVRP_Version == CluVRPVersion.Strong) { cluVRPLocalSearchs(cluVRPSolution, instance, parameters); } // Verify if customer solution is correct if (parameters.CluVRP_Version == CluVRPVersion.Strong) { cluVRPSolution.verifyCustomerSolution(instance); } else if (parameters.CluVRP_Version == CluVRPVersion.Weak) { cluVRPSolution.verifyCustomerWeakSolution(instance); } // Update best solution if (cluVRPSolution.totalCustomerRouteDistance < bestSolution.totalCustomerRouteDistance) { bestSolution = cluVRPSolution; bestSolution.cluVRPIterations = iterator; } // Increase iterator iterator++; } // Return best solution return(bestSolution); }
// Swap Cluster heuristic (diff to the cluster levels because the customers paths has been builded) public static void swapClusters(CluVRPSolution solution, CluVRPInstance instance, Parameters parameters) { // Calculate old distances for each vehicle double[] bestVehicleDistance = new double[solution.clusterRouteForVehicule.Length]; for (int vehicleIt = 0; vehicleIt < bestVehicleDistance.Length; vehicleIt++) { bestVehicleDistance[vehicleIt] = Functions.calculateTotalTravelDistance(solution.customersPaths, instance.customersDistanceMatrix, vehicleIt); } // For each vehicle for (int vehicle = 0; vehicle < solution.customersPaths.Length; vehicle++) { // Main cycle while (true) { // If solution improves try with new iteration bool solutionImproves = false; // For each cluster1 for (int clusterIt1 = 1; clusterIt1 + 1 < solution.customersPaths[vehicle].Length; clusterIt1++) { // For each cluster2 for (int clusterIt2 = 1; clusterIt2 + 1 < solution.customersPaths[vehicle].Length; clusterIt2++) { // If is not the same cluster if (clusterIt1 != clusterIt2) { // Calculate last and next cluster for cluster1 List <int> cluster1Last = solution.customersPaths[vehicle][clusterIt1 - 1]; List <int> cluster1 = solution.customersPaths[vehicle][clusterIt1]; List <int> cluster1Next = solution.customersPaths[vehicle][clusterIt1 + 1]; // Calculate last and next cluster for cluster2 List <int> cluster2Last = solution.customersPaths[vehicle][clusterIt2 - 1]; List <int> cluster2 = solution.customersPaths[vehicle][clusterIt2]; List <int> cluster2Next = solution.customersPaths[vehicle][clusterIt2 + 1]; // Perform swap solution.customersPaths[vehicle][clusterIt1] = cluster2; solution.customersPaths[vehicle][clusterIt2] = cluster1; Functions.Swap(solution.clusterRouteForVehicule[vehicle], clusterIt1, clusterIt2); // Calculate new distance double newDistance = Functions.calculateTotalTravelDistance(solution.customersPaths, instance.customersDistanceMatrix, vehicle); // If new distance is not better if (solution.vehiculeRouteDistance[vehicle] <= newDistance + 0.00001) { // Back the changes solution.customersPaths[vehicle][clusterIt1] = cluster1; solution.customersPaths[vehicle][clusterIt2] = cluster2; Functions.Swap(solution.clusterRouteForVehicule[vehicle], clusterIt1, clusterIt2); } else { // If new solution is better update distance solution.vehiculeRouteDistance[vehicle] = newDistance; solutionImproves = true; } } } } // If solution not improves jump to next vehicle if (!solutionImproves) { break; } } } // End return; }