//Same the Split function about but splits the map at x coordinates instead of y coordinates public static void splitX(newCity[] cityArray, float split, ref globalVars globalVars, ref List <newChild> childList) { //Distance variables float distance = 0; float totalDistance = 0; float distanceTL = 0; //Top Left distance float distanceTR = 0; //Top Right distance float distanceBR = 0; //Bottom Right Distance float distanceBL = 0; //Bottom Left distance //newCorner objects to find the 4 corners newCorner topLeft = new newCorner(float.MaxValue); newCorner topRight = new newCorner(float.MaxValue); newCorner bottomLeft = new newCorner(float.MaxValue); newCorner bottomRight = new newCorner(float.MaxValue); //Lists to store the cities above and below the split point List <int> topList = new List <int>(); List <int> topFinal = new List <int>(); List <int> bottomList = new List <int>(); List <int> bottomFinal = new List <int>(); //Check each city in the cityArray to see if it's //above or below the split point for (int c = 1; c < cityArray.Length + 1; c++) { //Above the split point if (cityArray[c - 1].xCoordinate > split) { topList.Add(c); //Add to the topList //Find cities closest to (split, 0) and (split, 100) float x1 = cityArray[c - 1].xCoordinate; float y1 = cityArray[c - 1].yCoordinate; float x2 = split; float y2 = 0; float y3 = 100; distanceBR = (float)Math.Sqrt((((x2 - x1)) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))); distanceTR = (float)Math.Sqrt((((x2 - x1)) * (x2 - x1)) + ((y3 - y1) * (y3 - y1))); //Check if the city is closest to (split, 0) and (split, 100) if (distanceTL < topLeft.coordinate) { topLeft.id = c; topLeft.coordinate = distanceTL; } if (distanceTR < topRight.coordinate) { topRight.id = c; topRight.coordinate = distanceTR; } } //At or below the split point else { bottomList.Add(c); //Add to the bottom list //Find cities closest to (split, 0) and (split, 100) float x1 = cityArray[c - 1].xCoordinate; float y1 = cityArray[c - 1].yCoordinate; float x2 = split; float y2 = 0; float y3 = 100; distanceBL = (float)Math.Sqrt((((x2 - x1)) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))); distanceTL = (float)Math.Sqrt((((x2 - x1)) * (x2 - x1)) + ((y3 - y1) * (y3 - y1))); //Check if the city is closest to (split, 0) and (split, 100) if (distanceBL < bottomLeft.coordinate) { bottomLeft.id = c; bottomLeft.coordinate = distanceBL; } if (distanceBR < bottomRight.coordinate) { bottomRight.id = c; bottomRight.coordinate = distanceBR; } } } //Discard current split if it resulted in a single city being //both bottomRight/bottomLeft or topRight/topLeft if ((topList.Count <= 1) || (bottomList.Count <= 1)) { return; } //Adding the corner cities to the top/bottomFinal lists //Removing the corner cities from the top/bottom lists topFinal.Add(topLeft.id); topFinal.Add(topRight.id); bottomFinal.Add(bottomRight.id); bottomFinal.Add(bottomLeft.id); topList.Remove(topLeft.id); topList.Remove(topRight.id); bottomList.Remove(bottomLeft.id); bottomList.Remove(bottomRight.id); //Call insertNode function to generate the new greedy paths InsertNode.insertNode(cityArray, topList, ref topFinal); InsertNode.insertNode(cityArray, bottomList, ref bottomFinal); //Combine the top and bottom paths to complete the tour topFinal.AddRange(bottomFinal); topFinal.Add(topFinal[0]); //If the path's distance wasn't the most recent path to be computed //find the distance of the path if (topFinal.SequenceEqual(globalVars.lastPath) == false) { globalVars.unique++; for (int d = 1; d < topFinal.Count; d++) { int xy1 = topFinal[d - 1] - 1; //Location of city A in city List int xy2 = topFinal[d] - 1; //Location of city B in city List //Find x and y coordinates of city A and B float x1 = cityArray[xy1].xCoordinate; float x2 = cityArray[xy2].xCoordinate; float y1 = cityArray[xy1].yCoordinate; float y2 = cityArray[xy2].yCoordinate; //Use distance equation to find the distance between city A and B //Add distance to totalDistance distance = (float)Math.Sqrt((((x2 - x1)) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))); totalDistance = totalDistance + distance; } //Store the most recent path to avoid //computing the same path multiple times globalVars.lastPath = topFinal; //Create newChild with topFinal path and corresponding distance newChild tempChild = new newChild(totalDistance, topFinal); //Rearange the tempChilds path so that it starts and ends with "1" tempChild.path.RemoveAt(topFinal.Count - 1); for (int i = 0; i < tempChild.path.Count; i++) { i = 0; if (tempChild.path[0] == 1) { break; } else { tempChild.path.Add(tempChild.path[0]); tempChild.path.RemoveAt(0); } } tempChild.path.Add(tempChild.path[0]); //If the new path distance is smaller than the //current smallest distance then replace //the smallest distance with the new distance if (tempChild.distance < globalVars.shortDistance) { globalVars.shortList.Clear(); globalVars.shortDistance = tempChild.distance; //Store the new shorter distance globalVars.shortList.AddRange(tempChild.path); //Store the corresponding path globalVars.shortSplit = split; //Store the current split value } //Sort the tempChild SortChild.sortChild(tempChild, ref globalVars, ref childList); SortChild.sortChild(tempChild, ref globalVars, ref globalVars.wisdomList); } }
public static void newGenChild(newCity[] cityArray, ref globalVars globalVars, ref List <newChild>[] genList, int rand, List <int> _tempList, List <int> _altPmx, double rand2) { //Temp variables int index; int tempVar; float distance = 0; float totalDistance = 0; //Random function and temp lists Random rnd = new Random(Guid.NewGuid().GetHashCode()); List <int> tempList = new List <int>(_tempList); List <int> altPmx = new List <int>(_altPmx); List <int> tempMut = new List <int>(); //Performs the pmx crossover by swapping the cities in the //parent's list according to the sublist from the other parent for (int j = rand; j < rand + globalVars.pmx; j++) { tempVar = tempList[j]; index = tempList.IndexOf(altPmx[j - rand]); tempList.RemoveAt(index); tempList.Insert(index, tempVar); tempList.RemoveAt(j); tempList.Insert(j, altPmx[j - rand]); } //Performs inversion mutation if rand2 was less than //the globalVars.mutation/100 if (rand2 < (globalVars.mutation / 100)) { tempMut.Clear(); rand = rnd.Next(1, tempList.Count - globalVars.pmx); for (int k = rand; k < rand + globalVars.pmx; k++) { tempMut.Add(tempList[k]); tempList.RemoveAt(k); tempList.Insert(rand, tempMut[k - rand]); } } tempList.Add(tempList[0]); //Calculate the tour distance for (int d = 1; d < tempList.Count; d++) { int xy1 = tempList[d - 1] - 1; //Location of city A in city List int xy2 = tempList[d] - 1; //Location of city B in city List //Find x and y coordinates of city A and B float x1 = cityArray[xy1].xCoordinate; float x2 = cityArray[xy2].xCoordinate; float y1 = cityArray[xy1].yCoordinate; float y2 = cityArray[xy2].yCoordinate; //Use distance equation to find the distance between city A and B //Add distance to totalDistance distance = (float)Math.Sqrt((((x2 - x1)) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))); totalDistance = totalDistance + distance; } //Create newChild with tempList path and corresponding distance newChild tempChild = new newChild(totalDistance, tempList); //Sort the tempChild node in the not current parent genList if (globalVars.genVar == 0) { SortChild.sortChild(tempChild, ref globalVars, ref genList[1]); } else { SortChild.sortChild(tempChild, ref globalVars, ref genList[0]); } //Sort child into the wisdomList to be used for WOC SortChild.sortChild(tempChild, ref globalVars, ref globalVars.wisdomList); }
//Sorts the newChild object according to its distance from smallest distance to largest distance //The List only contains the up to the top "globalVars.maxChildren" children public static void sortChild(newChild tempChild, ref globalVars globalVars, ref List <newChild> childList) { //If the list is empty, add the current child if (childList.Count == 0) { childList.Add(tempChild); } //If the list is not empty else { //If the list is currently full if (childList.Count == globalVars.maxChildren) { //If the distance of the last child in the list is less than the current child's distance, //don't sort the current child and return back to the NewGen class if (childList[globalVars.maxChildren - 1].distance < tempChild.distance) { return; } //If the distance of the last child in the list is greater than the current child's distance, //sort the current child as it is guarenteed to find a spot in the list else { //Check all the distances in the list and find where //the current child should be inserted by finding the //first element in the list that has a distance greater than //the current child and insert the child before that element for (int c = 0; c < childList.Count; c++) { if (tempChild.distance == childList[c].distance) { return; } else if (tempChild.distance < childList[c].distance) { childList.Insert(c, tempChild); childList.RemoveAt(globalVars.maxChildren); return; } } } } //If the list is not full, //sort the current child as it is guarenteed to find a spot in the list else { //Check all the distances in the list and find where //the current child should be inserted by finding the //first element in the list that has a distance greater than //the current child and insert the child before that element for (int c = 0; c < childList.Count; c++) { if (tempChild.distance == childList[c].distance) { return; } else if (tempChild.distance < childList[c].distance) { childList.Insert(c, tempChild); return; } //If the current child needs to be the //last item in the list for the first time else if (c == childList.Count - 1) { childList.Add(tempChild); return; } } } } }
static void Main(string[] args) { //Code needed to run the Windows Form Application Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); string fileName = "Random22.TSP"; //File name being tested //Variables to keep track of execution time Stopwatch stopWatch = new Stopwatch(); float time1 = 0; string time2 = null; string timer = null; stopWatch.Start(); //Start Stopwatch //Temp float to keep track of //shortest distance of each generation float tempDistance = float.MaxValue; int z = 0; //Temp variable int gen = 0; //Keeps track of current generation int count = 0; //Count variable double split = 2; //Split variables float split2 = 0; float distance = 0; //Distance variables float totalDistance = 0; globalVars globalVars = new globalVars(); //Object to hold "global" variables List <newChild>[] genList = new List <newChild> [2]; //Array to hold the children of each generation genList[0] = new List <newChild>(); //Swaps between holding the parents and children of a generation genList[1] = new List <newChild>(); //Swaps between holding the parents and children of a generation //Reads file to find # of lines //Stores (# of lines - 7) to get the number of cities in the file string[] lines = File.ReadAllLines(fileName); int newLength = lines.Length - 7; //Array of newCity objects with size = # of cities newCity[] cityArray = new newCity[newLength]; //Stores city data string line; System.IO.StreamReader file = new System.IO.StreamReader(fileName); while ((line = file.ReadLine()) != null) { //Ignore first 7 lines of the file //8th line is where the city data begins if (count >= 7) { string[] data = line.Split(' '); //Split and store the city data in data string array //Create newCity object using data pulled from data array (ID, x Coordinate, y Coordinate) //Store each newCity object in newCity array cityArray[count - 7] = new newCity(Int32.Parse(data[0]), float.Parse(data[1]), float.Parse(data[2])); } count++; } //Close File file.Close(); //If input for GA is choosen to be random if (globalVars.random == true) { Console.WriteLine("Random Inputs"); Random rnd = new Random(); List <int> temp1 = new List <int>(); //Temp list //Create a list with all the cities in it for (int l = 0; l < newLength; l++) { temp1.Add(cityArray[l].id); } temp1.RemoveAt(0); //Remove "1" from the list //Create "population size" of random tours for (int r = 0; r < globalVars.maxChildren; r++) { List <int> temp2 = new List <int>(temp1); int n = temp2.Count; //Scramble the list containing the cities while (n > 1) { n--; int rand = rnd.Next(n + 1); z = temp2[rand]; temp2[rand] = temp2[n]; temp2[n] = z; } //Add "1" to the start and end of the list to complete the tour temp2.Insert(0, 1); temp2.Add(1); //Calculate the tour distance for (int d = 1; d < temp2.Count; d++) { int xy1 = temp2[d - 1] - 1; //Location of city A in city List int xy2 = temp2[d] - 1; //Location of city B in city List //Find x and y coordinates of city A and B float x1 = cityArray[xy1].xCoordinate; float x2 = cityArray[xy2].xCoordinate; float y1 = cityArray[xy1].yCoordinate; float y2 = cityArray[xy2].yCoordinate; //Use distance equation to find the distance between city A and B //Add distance to totalDistance distance = (float)Math.Sqrt((((x2 - x1)) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))); totalDistance = totalDistance + distance; } //Create the newChild object using the randomized list //and the corresponding distance and then sort the child in genList[0] newChild tempChild = new newChild(totalDistance, temp2); SortChild.sortChild(tempChild, ref globalVars, ref genList[0]); } } //If input for GA is choosen to use the tours found by the greedy algorithm else { Console.WriteLine("Greedy Inputs"); //Split the map of cities at y = split and x = split //to generate solutions to use as the initial parents for the GA for (split = 2; split < 100; split += 0.5) { split2 = Convert.ToSingle(split); //Call the split function to split the map of cities at y = split Split.splitY(cityArray, split2, ref globalVars, ref genList[0]); //Call the split function to split the map of cities at x = split Split.splitX(cityArray, split2, ref globalVars, ref genList[0]); } } //Calls GA functions until the same distance //of the top child is found "globalVars.sameGen" times Console.WriteLine("Start GA"); for (z = 0; z < globalVars.sameGen; z++) { gen++; //Keeps track of the current generation //Calls newGen function to create the next generation //and return the child with the shortest distance newChild topChild = NewGen.newGen(cityArray, ref globalVars, ref genList); //Checks if the top child from the generation is more fit //than the top child from the last generation tempDistance = topChild.distance; //Console.WriteLine("gen " + gen + " " + tempDistance); if (tempDistance < globalVars.shortDistance) { //If the child is more fit than the previous generation //set the new distance as the shorest distance //and reset the GA stop condition z = 0; globalVars.shortDistance = tempDistance; globalVars.shortList.Clear(); globalVars.shortList.AddRange(topChild.path); } } //Prints the shortest tour/distance before the wisdom of crowds function is called Console.WriteLine("The Old Distance is " + globalVars.shortDistance); Console.WriteLine("The Old Path is " + string.Join(",", globalVars.shortList)); globalVars.shortDistance = 0; globalVars.shortList.Clear(); //Calls the Wisdom of Crowds function Console.WriteLine("Start WOC"); Console.WriteLine("WOC List Length = " + globalVars.wisdomList.Count); Crowds.crowds(newLength, ref globalVars); //Finds the distance for the Wisdom of Crowds tour for (int d = 1; d < globalVars.shortList.Count; d++) { int xy1 = globalVars.shortList[d - 1] - 1; //Location of city A in city List int xy2 = globalVars.shortList[d] - 1; //Location of city B in city List //If the WOC algorithm produced an imcomplete tour (not likely), //restart the application to find a clean solution //Bad solutions occurs when the WOC algorithm finds //an index that has no cities in it (all cities at index i are set to 0) if (xy1 < 0 || xy2 < 0) { Console.WriteLine("Bad Solution"); Console.WriteLine("Press any key to restart"); Console.ReadKey(); Application.Restart(); Environment.Exit(0); } //Find x and y coordinates of city A and B float x1 = cityArray[xy1].xCoordinate; float x2 = cityArray[xy2].xCoordinate; float y1 = cityArray[xy1].yCoordinate; float y2 = cityArray[xy2].yCoordinate; //Use distance equation to find the distance between city A and B //Add distance to totalDistance distance = (float)Math.Sqrt((((x2 - x1)) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))); totalDistance = totalDistance + distance; } globalVars.shortDistance = totalDistance; stopWatch.Stop(); //Stop Stopwatch //Print distance/path/time data Console.WriteLine("File = " + fileName); Console.WriteLine("The New Distance is " + globalVars.shortDistance); Console.WriteLine("The New Path is " + string.Join(",", globalVars.shortList)); time1 = stopWatch.ElapsedMilliseconds; time1 = (float)TimeSpan.FromMilliseconds(time1).TotalSeconds; time2 = stopWatch.ElapsedMilliseconds.ToString(); timer = time1.ToString(); Console.WriteLine("Execution time took " + time2 + " Milliseconds, or " + timer + " Seconds"); //Run Windows Form Application to graph the shortest path Application.Run(new GUI(cityArray, globalVars.shortList)); //Application.Restart(); //Environment.Exit(0); Console.ReadKey(); }