// 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; }
/* * * 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 }
/* * * Applies a list of local searchs * */ private void localSearch(CluVRPSolution newSolution) { // Create a local search handler for cluster-level problem CustomerStrongLocalSearch customerLocalSearch = new CustomerStrongLocalSearch(newSolution, instance, parameters.Customer_LS_TwoOpt_Iterations, parameters.Customer_LS_Relocate_Iterations, parameters.Customer_LS_Exchange_Iterations, parameters.Customer_LS_SwapCustomers ); // If random order for local searchs is activated if (parameters.Customer_LS_Order.Length == 0) { Functions.Shuffle(new Random(), this.localSearchsOrder); } // Execute local search in the correct order for (int i = 0; i < localSearchsOrder.Count; i++) { // Perform TwoOpt if (localSearchsOrder[i] == LocalSearch.TwoOpt && parameters.Customer_LS_TwoOpt_Iterations != 0) { var totalWatch = System.Diagnostics.Stopwatch.StartNew(); customerLocalSearch.twoOpt(); customerLocalSearch.solution.customer_twoOpt_time += totalWatch.ElapsedMilliseconds; } // Perform Relocate if (localSearchsOrder[i] == LocalSearch.Relocate && parameters.Customer_LS_Relocate_Iterations != 0) { var totalWatch = System.Diagnostics.Stopwatch.StartNew(); customerLocalSearch.relocate(); customerLocalSearch.solution.customer_relocate_time += totalWatch.ElapsedMilliseconds; } // Perform Exchange if (localSearchsOrder[i] == LocalSearch.Exchange && parameters.Customer_LS_Exchange_Iterations != 0) { var totalWatch = System.Diagnostics.Stopwatch.StartNew(); customerLocalSearch.exchange(); customerLocalSearch.solution.customer_exchange_time += totalWatch.ElapsedMilliseconds; } // Perform Customer Swap if (localSearchsOrder[i] == LocalSearch.SwapCustomers && parameters.Customer_LS_SwapCustomers != 0) { var totalWatch = System.Diagnostics.Stopwatch.StartNew(); customerLocalSearch.swapCustomers(); customerLocalSearch.solution.customer_swapCustomers_time += totalWatch.ElapsedMilliseconds; } } // Set the solution newSolution = customerLocalSearch.solution; }
/* * * Create a complete Greedy Randomized Solution (with cluster and customers) * */ private CluVRPSolution constructGreedyRandomizedSolution(List <int>[] customersOnVehicle, double alpha) { // Init variables int vehiclesNumber = customersOnVehicle.Length; List <int>[] customersCircuit = new List <int> [vehiclesNumber]; double[] vehiculeTotalDistance = new double[vehiclesNumber]; // For each vehicule cluster-route for (int vehicle = 0; vehicle < customersCircuit.Length; vehicle++) { // Init customer circuit for i-vehicle List <int> customersToVisit = customersOnVehicle[vehicle].ToList <int>(); customersCircuit[vehicle] = new List <int>(); // Add depot as first customer customersCircuit[vehicle].Add(1); // While exists customers to visit while (customersToVisit.Count > 0) { // Last customer int lastCustomer = customersCircuit[vehicle][customersCircuit[vehicle].Count - 1]; // Create RCL for customer List <int> customerRCL = buildCustomerRCL(customersToVisit, lastCustomer, alpha); // Select customer for RCL int customerSelected = Functions.selectRandomElement(customerRCL); // Add customer to the path customersCircuit[vehicle].Add(customerSelected); // Quit visited customer customersToVisit.Remove(customerSelected); } // Add depot as final customer customersCircuit[vehicle].Add(1); // Calculte total inter-cluster distance vehiculeTotalDistance[vehicle] = Functions.calculateCustomerTravelDistance(customersCircuit[vehicle], instance.customersDistanceMatrix); } // Set solution CluVRPSolution newSolution = new CluVRPSolution(instance); newSolution.setWeakCostumerSolution(customersCircuit, vehiculeTotalDistance); // Return solution return(newSolution); }
// 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; }
// 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; }
internal void logTimeAndIterations(CluVRPSolution solution, string instance) { string line = instance + '\t' + solution.cluVRPIterations.ToString() + '\t' + //solution.clusterLevelIterations.ToString() + '\t' + //solution.customerLevelIterations.ToString() + '\t' + //solution.LSCycleterations.ToString() + '\t' + (solution.clusterLevelTime).ToString() + '\t' + (solution.customerLevelTime).ToString() + '\t' + solution.cluster_LSCycle_iterations.ToString() + '\t' + solution.customer_LSCycle_iterations.ToString() + '\t' + (solution.cluster_LSCycleTime).ToString() + '\t' + (solution.customer_LSCycleTime).ToString() + '\t' + solution.cluvrp_swapClusters_iterations.ToString() + '\t' + solution.cluvrp_swapClusters_time.ToString() + '\t' + solution.cluvrp_swapVehicle_iterations.ToString() + '\t' + solution.cluvrp_swapVehicle_time.ToString() + '\t' + solution.cluster_twoOpt_iterations.ToString() + '\t' + (solution.cluster_twoOpt_time).ToString() + '\t' + solution.cluster_relocate_iterations.ToString() + '\t' + (solution.cluster_relocate_time).ToString() + '\t' + solution.cluster_exchange_iterations.ToString() + '\t' + (solution.cluster_exchange_time).ToString() + '\t' + solution.cluster_swapClusters_iterations.ToString() + '\t' + (solution.cluster_swapClusters_time).ToString() + '\t' + solution.cluster_swapVehicle_iterations.ToString() + '\t' + (solution.cluster_swapVehicle_time).ToString() + '\t' + solution.cluster_insertVehicle_iterations.ToString() + '\t' + (solution.cluster_insertVehicle_time).ToString() + '\t' + solution.customer_twoOpt_iterations.ToString() + '\t' + (solution.customer_twoOpt_time).ToString() + '\t' + solution.customer_relocate_iterations.ToString() + '\t' + (solution.customer_relocate_time).ToString() + '\t' + solution.customer_exchange_iterations.ToString() + '\t' + (solution.customer_exchange_time).ToString() + '\t' + solution.customer_swapCustomers_iterations.ToString() + '\t' + (solution.customer_swapCustomers_time).ToString(); try { using (System.IO.StreamWriter file = System.IO.File.AppendText(logFilePath + "_time")) { file.WriteLine(line); if (verbose) { Console.WriteLine(line); } } } catch (Exception e) { Console.WriteLine(e.ToString()); } }
/* * * Grasp(): * M <- calculateCustomerDistance * BestSolution = 0 * While(StopCondition) * Solution <- ConstructGreedySolution() * NewSolution <- LocalSearch(solution) * if NewSolution isBetterThan BestSolution * BestSolution = NewSolution * return BestSolution * */ override public void Grasp() { // Set iterator int iterator = 0; int totalIterations = parameters.Customer_GRASPIterations; double alpha = parameters.Customer_Alpha; // Main cycle while (iterator < totalIterations) { // For random alpha if (parameters.Customer_Alpha == -1) { Random rnd = new Random(); alpha = rnd.Next(0, 11) / 10.0; } // Calculate new initial solution CluVRPSolution newSolution = constructGreedyRandomizedSolution(alpha); // Local search var totalLSWatch = System.Diagnostics.Stopwatch.StartNew(); double routeDistance = newSolution.totalCustomerRouteDistance; for (int i = 0; i < 1; i++) { // Perform local searchs this.localSearch(newSolution); // For control of best iteration number if (newSolution.totalCustomerRouteDistance < routeDistance) { newSolution.cluster_LSCycle_iterations = i; routeDistance = newSolution.totalCustomerRouteDistance; } } newSolution.customer_LSCycleTime += totalLSWatch.ElapsedMilliseconds; // Update Best solution if (newSolution.totalCustomerRouteDistance < solution.totalCustomerRouteDistance) { solution.setCostumerSolution(newSolution.customersPaths, newSolution.vehiculeRouteDistance); solution.bestCustomerLSOrder = localSearchsOrder; solution.customerLevelIterations = iterator; solution.customer_LSCycle_iterations = newSolution.customer_LSCycle_iterations; solution.customer_twoOpt_iterations = newSolution.customer_twoOpt_iterations; solution.customer_relocate_iterations = newSolution.customer_relocate_iterations; solution.customer_exchange_iterations = newSolution.customer_exchange_iterations; solution.customer_swapCustomers_iterations = newSolution.customer_swapCustomers_iterations; solution.customer_LSCycleTime = newSolution.customer_LSCycleTime; solution.customer_twoOpt_time = newSolution.customer_twoOpt_time; solution.customer_relocate_time = newSolution.customer_relocate_time; solution.customer_exchange_time = newSolution.customer_exchange_time; solution.customer_swapCustomers_time = newSolution.customer_swapCustomers_time; } // Increace iterator iterator++; } //End return; }
/* * * Create a complete Greedy Randomized Solution (with cluster and customers) * */ private CluVRPSolution constructGreedyRandomizedSolution(double alpha) { // Init variables int[][] originalClusters = instance.clusters; List <int>[] clusterRoute = solution.clusterRouteForVehicule; List <int>[][] customersCircuit = new List <int> [clusterRoute.Length][]; Tuple <int, int> customersConnectClusters = new Tuple <int, int>(0, 0); double[] vehiculeTotalDistance = new double[instance.vehicles]; // Start from depot int startingCustomer = 1; int[][][] clusterRouteWithCustomers = this.clusterRouteWithCustomers(originalClusters, clusterRoute); // For each vehicule cluster-route for (int vehicle = 0; vehicle < clusterRoute.Length; vehicle++) { // For each cluster in the i-vehicle route int numbersOfClusters = clusterRoute[vehicle].Count; int[][] clustersOneVehicle = clusterRouteWithCustomers[vehicle]; customersCircuit[vehicle] = new List <int> [numbersOfClusters]; // If vehicle has not travel if (clusterRoute[vehicle].Count == 2) { customersCircuit[vehicle] = new List <int> [2]; customersCircuit[vehicle][0] = new List <int>(); customersCircuit[vehicle][1] = new List <int>(); customersCircuit[vehicle][0].Add(1); customersCircuit[vehicle][1].Add(1); vehiculeTotalDistance[vehicle] = 0; continue; } // Visit all cluster for the i-vehicle for (int i = 0; i < numbersOfClusters; i++) { // Add actual (initial of cluster) customer customersCircuit[vehicle][i] = new List <int>(); customersCircuit[vehicle][i].Add(startingCustomer); // For best customer to conect actual cluster to the next // If the cluster only has 1 customer, you only have to know the // customer for the next cluster if (i + 1 < numbersOfClusters && clustersOneVehicle[i].Length > 1) { customersConnectClusters = bestCustomersBetween2Clusters(clustersOneVehicle[i], clustersOneVehicle[i + 1], startingCustomer); } else if (i + 1 < numbersOfClusters && clustersOneVehicle[i].Length == 1) { int nextCustomer = bestNextCustomer(startingCustomer, clustersOneVehicle[i + 1]); customersConnectClusters = new Tuple <int, int>(startingCustomer, nextCustomer); } // Convert array to list List <int> customersToVisit = clustersOneVehicle[i].OfType <int>().ToList(); // Remove initial and final customers customersToVisit.Remove(startingCustomer); customersToVisit.Remove(customersConnectClusters.Item1); // While exists customers to visit while (customersToVisit.Count > 0) { // Create RCL for customer List <int> customerRCL = buildCustomerRCL(startingCustomer, customersToVisit, alpha); // Select customer for RCL int customerSelected = Functions.selectRandomElement(customerRCL); // Add customer to the path customersCircuit[vehicle][i].Add(customerSelected); // Quit visited customer customersToVisit.Remove(customerSelected); // Set new actual customer startingCustomer = customerSelected; } // Add final customer that connect to i+1 cluster // In the final cluster the next customer is 0 // the it has not be added if (clustersOneVehicle[i].Length > 1 && i + 1 < numbersOfClusters) { customersCircuit[vehicle][i].Add(customersConnectClusters.Item1); } // Next customer of next cluster startingCustomer = customersConnectClusters.Item2; } // Calculte total inter-cluster distance vehiculeTotalDistance[vehicle] = Functions.calculateTotalTravelDistance(customersCircuit, instance.customersDistanceMatrix, vehicle); } // Set solution CluVRPSolution newSolution = new CluVRPSolution(instance); newSolution.setCostumerSolution(customersCircuit, vehiculeTotalDistance); // Return solution return(newSolution); }
// Main Function static void GraspProcedure(string parametersFilePath, string instanceSetFilePath, string logFilePath, double[] solutionToCompare, CluVRPVersion cluVRPVersion) { // Star watch to calculate total process time var totalWatch = System.Diagnostics.Stopwatch.StartNew(); // For watch for each instance execution long elapsedMs = 0; // Number of instances int instancesNumber = solutionToCompare.Length; // For best results Dictionary <CluVRPInstance, CluVRPSolution> bestSolutionForInstance = new Dictionary <CluVRPInstance, CluVRPSolution>(); CluVRPSolution solution; double[] bestSolutionTotalDistance = new double[instancesNumber]; double[] bestSolutionPropDistance = new double[instancesNumber]; double[] bestSolutionTime = new double[instancesNumber]; Functions.Populate(bestSolutionTotalDistance, double.MaxValue); string[] bestSolutionParameters = new string[instancesNumber]; // For Average results double[] totalDistance = new double[instancesNumber]; double[] totalTime = new double[instancesNumber]; double[] solutionAvgPropDistance = new double[instancesNumber]; int[] instanceOKsolutions = new int[instancesNumber]; // Get parameters to run instances List <Parameters> parametersList = Parameters.parseParameterFile(parametersFilePath); // Get logger Logger logger = Logger.GetInstance(); // To logger verbose on/off logger.setVerbose(false); logger.setLogFilePath(logFilePath); // Get instances CluVRPInstance[] instancias = InstanceParser.loadGVRPSetOfInstances(instanceSetFilePath); // Log run logger.logLine("*****************************************************" + '\n' + "* STARTING TEST:" + '\n' + "* DATE -> " + DateTime.Now.ToString() + '\n' + "* CONFIG -> " + parametersFilePath + '\n' + "* SET INSTANCE -> " + instanceSetFilePath + '\n' + "* LOG FILE -> " + logger.getLogFilePath() + '\n' + "*****************************************************" + '\n'); // For each instance int instanceIterator = 0; foreach (CluVRPInstance instance in instancias) { // For this instance double distance; // Create new solution solution = new CluVRPSolution(instance); // For each parameter configuration foreach (Parameters parameters in parametersList) { // Star watch to calculate time var watch = System.Diagnostics.Stopwatch.StartNew(); // If CluVRP_Version in parameters is None(3) it has to be taken from command line if (parameters.CluVRP_Version == CluVRPVersion.None) { parameters.CluVRP_Version = cluVRPVersion; } // Actual Parameter string actualParameters = Functions.parametersToString(parameters); //logger.logLine(actualParameters); // Calculate solution for normal CluVRP or weak cluster constrains solution = CluVRPGrasp.Grasp(instance, parameters); // If not possible solution if (solution.clusterRouteForVehicule == null) { continue; } // Increase instance OK solution iteration instanceOKsolutions[instanceIterator]++; // For this instance solution distance = solution.totalCustomerRouteDistance; // Izquierdo instances results are not integers if (instance.instance_type == Instance.GoldenIzquierdo) { distance = Math.Truncate(100 * distance) / 100; } else { distance = Math.Truncate(distance); } // Stop timer watchers watch.Stop(); // Set execution time elapsedMs = watch.ElapsedMilliseconds; double elapsedSeconds = Math.Round(elapsedMs * 1.0 / 1000, 2); // Update solution results totalDistance[instanceIterator] += distance; totalTime[instanceIterator] += elapsedSeconds; // Update individual instance solution if (distance < bestSolutionTotalDistance[instanceIterator]) { bestSolutionTotalDistance[instanceIterator] = distance; bestSolutionPropDistance[instanceIterator] = (distance - solutionToCompare[instanceIterator]) * 100 / solutionToCompare[instanceIterator]; bestSolutionPropDistance[instanceIterator] = Math.Truncate(100 * bestSolutionPropDistance[instanceIterator]) / 100; bestSolutionParameters[instanceIterator] = actualParameters; bestSolutionTime[instanceIterator] = elapsedSeconds; bestSolutionForInstance[instance] = solution; } } // Calculate averages double averageDistance = totalDistance[instanceIterator] / instanceOKsolutions[instanceIterator]; double averageTime = totalTime[instanceIterator] / instanceOKsolutions[instanceIterator]; averageTime = Math.Round(averageTime, 2); double averagePropDistance = (averageDistance - solutionToCompare[instanceIterator]) * 100 / solutionToCompare[instanceIterator]; averagePropDistance = Math.Truncate(100 * averagePropDistance) / 100; bestSolutionPropDistance[instanceIterator] = Math.Truncate(100 * bestSolutionPropDistance[instanceIterator]) / 100; solutionAvgPropDistance[instanceIterator] = averagePropDistance; // For log solution string s_distance; string s_averageDistance; string s_bestSolutionPropDistance = bestSolutionPropDistance[instanceIterator].ToString("0.00"); string s_bestSolutionTime = bestSolutionTime[instanceIterator].ToString("0.00"); string s_averagePropDistance = averagePropDistance.ToString("0.00"); string s_averageTime = averageTime.ToString("0.00"); string s_fileName = Path.GetFileName(instancias[instanceIterator].file_name); if (instance.instance_type == Instance.GoldenIzquierdo) { s_distance = bestSolutionTotalDistance[instanceIterator].ToString("0.00"); s_averageDistance = averageDistance.ToString("0.00"); } else { s_distance = bestSolutionTotalDistance[instanceIterator].ToString("0"); s_averageDistance = averageDistance.ToString("0"); } // Print solution string outLine = s_fileName + '\t' + '\t' + s_distance + '\t' + s_bestSolutionPropDistance + "%" + '\t' + s_bestSolutionTime + "s" + '\t' + '\t' + s_averageDistance + '\t' + s_averagePropDistance + "%" + '\t' + s_averageTime + "s"; logger.logLine(outLine); logger.logTimeAndIterations(solution, instance.file_name); // Increase distance counter instanceIterator++; } // Stop timer watchers totalWatch.Stop(); var totalElapsedseconds = totalWatch.ElapsedMilliseconds / 1000; // Total values string s_totalPropBestDistance = (bestSolutionPropDistance.Sum() / instancesNumber).ToString("0.00"); string s_totalPropAvgDistance = (solutionAvgPropDistance.Sum() / instancesNumber).ToString("0.00"); // Show parameters for best solution logger.logLine(""); logger.logLine("*************************************"); logger.logLine("* PARAMETERS FOR BEST SOLUTIONS: *"); logger.logLine("*************************************"); logger.logLine("TOTAL TIME -> " + totalElapsedseconds + " seconds"); logger.logLine("TOTAL BEST PROP DISTANCE -> " + s_totalPropBestDistance + "%"); logger.logLine("TOTAL AVG PROP DISTANCE -> " + s_totalPropAvgDistance + "%"); logger.logLine(""); for (int i = 0; i < bestSolutionParameters.Length; i++) { logger.logLine("-----------------------------------------------------------------"); logger.logLine(""); logger.logLine("CONFIGURATION FOR INSTANCE " + i); logger.logLine("*****************************"); logger.logLine(bestSolutionParameters[i].ToString()); } // Draw PNG solution foreach (CluVRPInstance instance in bestSolutionForInstance.Keys) { //CluVRPSolution.solutionDrawPythonCode(instance, bestSolutionForInstance[instance]); } // Pause //System.Console.ReadKey(); // End return; }
// Main Function static void GraspProcedureCycleParameters(string parametersFilePath, string instanceSetFilePath, string logFilePath, double[] solutionToCompare) { // Star watch to calculate total process time var totalWatch = System.Diagnostics.Stopwatch.StartNew(); // For watch for each instance execution long elapsedMs = 0; // For best solution set Dictionary <CluVRPInstance, CluVRPSolution> bestSolutionForInstance = new Dictionary <CluVRPInstance, CluVRPSolution>(); CluVRPSolution solution; double[] bestIndividualTotalDistance = new double[solutionToCompare.Length]; double[] bestIndividualPropDistance = new double[solutionToCompare.Length]; double[] bestIndividualTime = new double[solutionToCompare.Length]; Functions.Populate(bestIndividualTotalDistance, double.MaxValue); string[] bestIndividualParameteres = new string[solutionToCompare.Length]; double[] bestSolPropDistances = new double[solutionToCompare.Length]; Functions.Populate(bestSolPropDistances, double.MaxValue); double[] bestSolDistances = new double[solutionToCompare.Length]; double[] bestSolTimes = new double[solutionToCompare.Length]; List <List <LocalSearch> > bestSolClusterLSOrder = new List <List <LocalSearch> >(); List <List <LocalSearch> > bestSolCustomerLSOrder = new List <List <LocalSearch> >(); string bestSolParameters = ""; double totalAvg = double.MaxValue; double totalAvgTime = double.MaxValue; // Get parameters to run instances List <Parameters> parametersList = Parameters.parseParameterFile(parametersFilePath); // Get logger Logger logger = Logger.GetInstance(); // To logger verbose on logger.setVerbose(true); logger.setLogFilePath(logFilePath); // Get instances CluVRPInstance[] instancias = InstanceParser.loadGVRPSetOfInstances(instanceSetFilePath); // Log run logger.logLine("*****************************************************" + '\n' + "* STARTING TEST:" + '\n' + "* CONFIG -> " + parametersFilePath + '\n' + "* SET INSTANCE -> " + instanceSetFilePath + '\n' + "* LOG FILE -> " + logger.getLogFilePath() + '\n' + "******************************************************" + '\n'); // For each parameter configuration foreach (Parameters parameters in parametersList) { // String for parameter set and print logger.logLine("=============================================" + '\n' + "= EXECUTING NEW TEST CASE =" + '\n' + "=============================================" + '\n'); string actualParameters = Functions.parametersToString(parameters); logger.logLine(actualParameters); // For this configuration run double[] propDistances = new double[solutionToCompare.Length]; double[] distances = new double[solutionToCompare.Length]; double[] times = new double[solutionToCompare.Length]; List <List <LocalSearch> > LSClusterOrder = new List <List <LocalSearch> >(); List <List <LocalSearch> > LSCustomerOrder = new List <List <LocalSearch> >(); // For each instance int instanceCounter = 0; foreach (CluVRPInstance instance in instancias) { // Star watch to calculate time var watch = System.Diagnostics.Stopwatch.StartNew(); // Set max distance value double distance = 0; string fitAlgoBestSol = ""; // Create a new solution solution = new CluVRPSolution(instance); // Calculate solution for normal CluVRP or weak cluster constrains solution = CluVRPGrasp.Grasp(instance, parameters); // If not possible solution if (solution.clusterRouteForVehicule == null) { logger.logLine(instance.file_name + '\t' + "No solution for this instance"); propDistances[instanceCounter] = 10; instanceCounter++; continue; } // Sets strings to show - FOR DEBUG string s1 = instance.file_name + '\t' + solution.totalCustomerRouteDistance + '\t' + parameters.Cluster_AlphaCapacity + '\t' + parameters.Cluster_AlphaDistance + '\t'; //Console.WriteLine(s1); // For this instance solution distance = solution.totalCustomerRouteDistance; //solution.customersPaths[0][5][0] = 20; //solution.customersPaths[0][5][1] = 19; //distance = Functions.calculateTotalTravelDistance(solution.customersPaths, instance.customersDistanceMatrix); if (instance.instance_type == Instance.GoldenIzquierdo) { distance = Math.Truncate(100 * distance) / 100; } else { distance = Math.Truncate(distance); } LSClusterOrder.Add(solution.bestClusterLSOrder); LSCustomerOrder.Add(solution.bestCustomerLSOrder); // Stop timer watchers watch.Stop(); // Set execution time elapsedMs = watch.ElapsedMilliseconds; double elapsedSeconds = Math.Round(elapsedMs * 1.0 / 1000, 2); // Update solution results distances[instanceCounter] = distance; propDistances[instanceCounter] = (distance - solutionToCompare[instanceCounter]) * 100 / solutionToCompare[instanceCounter]; propDistances[instanceCounter] = Math.Truncate(100 * propDistances[instanceCounter]) / 100; times[instanceCounter] = elapsedSeconds; // Update individual instance solution if (distances[instanceCounter] < bestIndividualTotalDistance[instanceCounter]) { bestIndividualTotalDistance[instanceCounter] = distances[instanceCounter]; bestIndividualPropDistance[instanceCounter] = (distance - solutionToCompare[instanceCounter]) * 100 / solutionToCompare[instanceCounter]; bestIndividualPropDistance[instanceCounter] = Math.Truncate(100 * bestIndividualPropDistance[instanceCounter]) / 100; bestIndividualParameteres[instanceCounter] = actualParameters; bestIndividualTime[instanceCounter] = elapsedSeconds; bestSolutionForInstance[instance] = solution; } // Log solution string s_distance; if (instance.instance_type == Instance.GoldenIzquierdo) { s_distance = distance.ToString("0.00"); } else { s_distance = distance.ToString("0"); } string outLine = instance.file_name + '\t' + s_distance + '\t' + propDistances[instanceCounter] + "%" + '\t' + (elapsedMs * 1.0 / 1000).ToString("0.00") + "s" + '\t' + fitAlgoBestSol; logger.logLine(outLine); // Increase distance counter instanceCounter++; } // Show total final proporcional differente and times totalAvg = Math.Truncate(100 * propDistances.Sum() / propDistances.Length) / 100; totalAvgTime = Math.Truncate(100 * times.Sum() / times.Length) / 100; logger.logLine(""); logger.logLine("####################################"); logger.logLine("# TOTAL PROP DIFFERENCE -> " + totalAvg); logger.logLine("# TOTAL TIME -> " + times.Sum().ToString("0.00")); logger.logLine("# TOTAL AVERAGE TIME -> " + totalAvgTime.ToString("0.00")); logger.logLine("####################################"); // Compare best AVG if (propDistances.Sum() < bestSolPropDistances.Sum()) { // Update to new best set solution bestSolPropDistances = propDistances; bestSolParameters = actualParameters; bestSolDistances = distances; bestSolTimes = times; bestSolClusterLSOrder = LSClusterOrder; bestSolCustomerLSOrder = LSCustomerOrder; totalAvg = Math.Truncate(100 * bestSolPropDistances.Sum() / bestSolPropDistances.Length) / 100; totalAvgTime = Math.Truncate(100 * bestSolTimes.Sum() / bestSolTimes.Length) / 100; bestSolTimes = times; // Show AVG distance logger.logLine(""); logger.logLine("-----------------------------------------------------------------------"); logger.logLine("-------------------------NEW BEST DISTANCE-----------------------------"); logger.logLine("-----------------------------------------------------------------------"); //logger.logLine("NEW PROPORTIONAL BEST SET DISTANCE -> " + bestSolPropDistances.Sum()); logger.logLine("DISTANCES -> " + Functions.arrayToString(bestSolDistances)); logger.logLine("PROP DISTANCES -> " + Functions.arrayToString(bestSolPropDistances)); logger.logLine("TOTAL AVERAGE DIFERENCE DISTANCE -> " + totalAvg); logger.logLine("TOTAL AVERAGE TIME -> " + totalAvgTime); logger.logLine("-----------------------------------------------------------------------"); logger.logLine("-----------------------------------------------------------------------"); logger.logLine("-----------------------------------------------------------------------"); } // New line for new config logger.logLine(""); } // Stop timer watchers totalWatch.Stop(); var totalElapsedseconds = totalWatch.ElapsedMilliseconds / 1000; // Log best solution logger.logLine(""); logger.logLine("******************"); logger.logLine("* BEST SOLUTION: *"); logger.logLine("******************"); logger.logLine("TOTAL TIME -> " + totalElapsedseconds + " seconds"); //logger.logLine("PROPORTIONAL BEST SET DISTANCE -> " + bestSolPropDistances.Sum()); //logger.logLine("DISTANCES -> " + Functions.arrayToString(bestSolDistances)); //logger.logLine("PROPORTIONA DIFF DISTANCES -> " + Functions.arrayToString(bestSolPropDistances)); totalAvg = Math.Truncate(100 * bestSolPropDistances.Sum() / bestSolPropDistances.Length) / 100; totalAvgTime = Math.Truncate(100 * bestSolTimes.Sum() / bestSolTimes.Length) / 100; logger.logLine("TOTAL AVERAGE DIFERENCE DISTANCE -> " + totalAvg); logger.logLine("TOTAL AVERAGE TIME -> " + totalAvgTime); logger.logLine(""); logger.logLine("LIST OF RESULTS"); logger.logLine("***************"); for (int i = 0; i < bestSolDistances.Length; i++) { string outLine = instancias[i].file_name + '\t' + bestSolDistances[i] + '\t' + bestSolPropDistances[i] + "%" + '\t' + bestSolTimes[i]; logger.logLine(outLine); } logger.logLine(""); logger.logLine("PARAMETERS: "); logger.logLine("***********"); logger.logLine(bestSolParameters); logger.logLine("CLUSTER LS ORDER:"); logger.logLine("*****************"); for (int i = 0; i < bestSolClusterLSOrder.Count; i++) { logger.logLine((Functions.arrayToString(bestSolClusterLSOrder[i]))); } logger.logLine(""); logger.logLine("CUSTOMER LS ORDER:"); logger.logLine("******************"); for (int i = 0; i < bestSolCustomerLSOrder.Count; i++) { logger.logLine((Functions.arrayToString(bestSolCustomerLSOrder[i]))); } logger.logLine(""); logger.logLine(""); logger.logLine("============================"); logger.logLine("= BEST INDIVIDUAL RESULTS =:"); logger.logLine("============================"); totalAvg = Math.Truncate(100 * bestIndividualPropDistance.Sum() / bestIndividualPropDistance.Length) / 100; totalAvgTime = Math.Truncate(100 * bestIndividualTime.Sum() / bestIndividualTime.Length) / 100; //logger.logLine("DISTANCES -> " + Functions.arrayToString(bestIndividualTotalDistance)); //logger.logLine("PROPORTIONA DIFF DISTANCES -> " + Functions.arrayToString(bestIndividualPropDistance)); //logger.logLine("PROPORTIONAL TOTAL DISTANCE -> " + bestIndividualPropDistance.Sum().ToString("00.00")); logger.logLine("TOTAL AVERAGE DIFERENCE DISTANCE -> " + totalAvg); logger.logLine("TOTAL AVERAGE TIME -> " + totalAvgTime); logger.logLine(""); logger.logLine("LIST OF RESULTS"); logger.logLine("***************"); for (int i = 0; i < bestIndividualTotalDistance.Length; i++) { string outLine = instancias[i].file_name + '\t' + bestIndividualTotalDistance[i] + '\t' + bestIndividualPropDistance[i] + "%" + '\t' + bestIndividualTime[i]; logger.logLine(outLine); } logger.logLine(""); for (int i = 0; i < bestSolClusterLSOrder.Count; i++) { logger.logLine("-----------------------------------------------------------------"); logger.logLine(""); logger.logLine("CONFIGURATION FOR INSTANCE " + i); logger.logLine("*****************************"); logger.logLine(bestIndividualParameteres[i].ToString()); } foreach (CluVRPInstance instance in bestSolutionForInstance.Keys) { CluVRPSolution.solutionDrawPythonCode(instance, bestSolutionForInstance[instance]); } // Pause //System.Console.ReadKey(); // End return; }
// 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); }
// 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; }