// Check if crossover points are good private bool GoodCrossover(int split_1_F, int split_1_M, int split_2_F, int split_2_M, EAPath Son, EAPath Daughter, bool blnTwoCommonNodes) { if (blnTwoCommonNodes) { if (ValidCrossover(split_1_F, Son, 2) // First crossover point for Son && ValidCrossover(split_1_F, Son, 1) // First crossover point for Son && ValidCrossover(split_1_M, Daughter, 2) // First crossover point for Daughter && ValidCrossover(split_1_M, Daughter, 1) // First crossover point for Daughter && ValidCrossover(split_1_F + split_2_M - split_1_M, Son, 2) // Second crossover point for Son && ValidCrossover(split_1_F + split_2_M - split_1_M, Son, 1) // Second crossover point for Son && ValidCrossover(split_1_M + split_2_F - split_1_F, Daughter, 2) // Second crossover point for Daughter && ValidCrossover(split_1_M + split_2_F - split_1_F, Daughter, 1)) // Second crossover point for Daughter { // Both crossover points are good return true; } else { // Some crossover point is bad return false; } } else { if (ValidCrossover(split_1_F, Son, 2) // First crossover point for Son && ValidCrossover(split_1_F, Son, 1) // First crossover point for Son && ValidCrossover(split_1_M, Daughter, 2) // First crossover point for Daughter && ValidCrossover(split_1_M, Daughter, 1)) // First crossover point for Daughter { // First crossover is good return true; } else { // First crossover is bad return false; } } }
// Algorithm specific implementation of the path planning protected override void DoPathPlanning() { // Disabled hiararchical decision making in EA. Since EA should have plenty of time. //if (HiararchicalSearch()) //{ // return; //} DateTime startTime2 = DateTime.Now; // Generate initial population CurGeneration = CreatePopulation(); DateTime stopTime2 = DateTime.Now; TimeSpan duration2 = stopTime2 - startTime2; double RunTime2 = duration2.TotalSeconds; if (ProjectConstants.DebugMode) { curRequest.SetLog("CreatePopulation took " + RunTime2 + " seconds.\n"); } // Sort based on CDF. Best at the end. CurGeneration.Sort(); //// Debug //CheckPathValidity(CurGeneration, "After CreatePopulation()"); // Remaining population size (e.g. 100-3=97) PRemain = ProjectConstants.EA_Population - ProjectConstants.EA_BestToKeep; // What's the best we have so far? CDF = CurGeneration[CurGeneration.Count - 1].CDF; Path = new List<Point>(); Path.AddRange(CurGeneration[CurGeneration.Count - 1].Path); // Prepare lists to store improvements List<double> Improvement = new List<double>(); Improvement.Add(0); List<double> RememberCDF = new List<double>(); RememberCDF.Add(CurGeneration[CurGeneration.Count - 1].CDF); startTime2 = DateTime.Now; // Iterate until converge or until certain number of iterations int count = 1; double epsilon = 1; while (epsilon > 0 && count < ProjectConstants.EA_Maximum_Run) { // If we already have the path, then no need to continue if (Math.Abs(CDF - Efficiency_UB) < 0.001) { break; } // Create a new generation // 0. Keep the best three to mid generation // (First three in new generation are the best three from last generation) NewGeneration = CurGeneration.GetRange(PRemain, ProjectConstants.EA_BestToKeep); //// Debug //CheckPathValidity(NewGeneration, "After Newgeneration keep best"); // 1. Select based on replace rate SelectPopulation(); //// Debug //CheckPathValidity(NewGeneration, "After SelectPopulation()"); // 2. Crossover based on crossover rate Crossover(); //// Debug //CheckPathValidity(NewGeneration, "After Crossover()"); // 3. Add best to keep to end of list and don't mutate those for (int i = 0; i < ProjectConstants.EA_BestToKeep; i++) { EAPath eap = new EAPath(); eap.CDF = NewGeneration[i].CDF; eap.DirPath.AddRange(NewGeneration[i].DirPath); eap.Path.AddRange(NewGeneration[i].Path); NewGeneration.Add(eap); } //// Debug //CheckPathValidity(NewGeneration, "After add best 3 to end"); // 4. Mutate based on mutate rate Mutate(); //// Debug //CheckPathValidity(NewGeneration, "After Mutate()"); // 5. Evaluate EvaluateFitness(); NewGeneration.Sort(); //// Debug //CheckPathValidity(NewGeneration, "After EvaluateFitness()"); // 6. Update CurGeneration.Clear(); CurGeneration.AddRange(NewGeneration.GetRange(NewGeneration.Count - ProjectConstants.EA_Population, ProjectConstants.EA_Population)); //// Debug //CheckPathValidity(CurGeneration, "After generating new CurGeneration"); // 7. Remember best and record improvement RememberCDF.Add(CurGeneration[ProjectConstants.EA_Population - 1].CDF); Improvement.Add(CurGeneration[ProjectConstants.EA_Population - 1].CDF - CDF); CDF = CurGeneration[ProjectConstants.EA_Population - 1].CDF; Path = new List<Point>(); Path.AddRange(CurGeneration[ProjectConstants.EA_Population - 1].Path); //// Debug //CheckPathValidity(NewGeneration, "After remember best and record improvement"); if (Improvement.Count < ProjectConstants.EA_Minimum_Run) { epsilon = 1; } else { epsilon = 0; for (int i = 0; i < ProjectConstants.EA_Epsilon_Run; i++) { epsilon += Improvement[Improvement.Count - 1 - i]; } epsilon = epsilon / ProjectConstants.EA_Epsilon_Run; } //// Debug //CheckPathValidity(NewGeneration, "After computing epsilon"); // 7. Increase counter count++; } // Evolution completed... Path = new List<Point>(); Path.AddRange(CurGeneration[CurGeneration.Count - 1].Path); // Report how many iterations if (ProjectConstants.DebugMode) { curRequest.SetLog("Algorithm ran " + count.ToString() + " iterations.\n"); } // Record EA time stopTime2 = DateTime.Now; duration2 = stopTime2 - startTime2; RunTime2 = duration2.TotalSeconds; if (ProjectConstants.DebugMode) { curRequest.SetLog("EA took " + RunTime2 + " seconds.\n"); // Print out improvement log curRequest.SetLog("Improvement: \n"); for (int i = 0; i < Improvement.Count; i++) { curRequest.SetLog(Improvement[i].ToString() + " "); } curRequest.SetLog("\n"); } // Cleaning up Improvement.Clear(); Improvement = null; }
// Function to actually generate seeds of various algorithms private bool GenerateSeeds(List<EAPath> AllPaths, PathPlanningRequest newRequest, AlgPathPlanning myAlg, int count) { for (int i = 0; i < count; i++) { switch (newRequest.AlgToUse) { case AlgType.CC: myAlg = new AlgCC(newRequest, mDist, mDiff, Efficiency_UB); break; case AlgType.LHCGWCONV: myAlg = new AlgGlobalWarming(newRequest, ModeCount, mDist, mDiff, Efficiency_UB); break; case AlgType.LHCGWPF: myAlg = new AlgGlobalWarming(newRequest, ModeCount, mDist, mDiff, Efficiency_UB); break; case AlgType.LHCRandom: myAlg = new AlgLHCRandom(newRequest, mDist, mDiff, Efficiency_UB); break; case AlgType.Random: myAlg = new AlgRandom(newRequest, mDist, mDiff, Efficiency_UB); break; case AlgType.TopTwoH: myAlg = new AlgTopTwo(newRequest, ModeCount, mModes, mDist, mDiff, Efficiency_UB); break; case AlgType.TopNH: myAlg = new AlgTopTwo(newRequest, ModeCount, mModes, mDist, mDiff, Efficiency_UB); break; default: break; } DateTime startTime2 = DateTime.Now; myAlg.PlanPath(); DateTime stopTime2 = DateTime.Now; TimeSpan duration2 = stopTime2 - startTime2; double RunTime2 = duration2.TotalSeconds; if (ProjectConstants.DebugMode) { curRequest.SetLog("Algorithm " + newRequest.AlgToUse + " took " + RunTime2 + " seconds.\n"); } EAPath eap = new EAPath(); eap.CDF = myAlg.GetCDF(); eap.Path.AddRange(myAlg.GetPath()); myAlg = null; // Add EAPath to population AllPaths.Add(eap); // If we already have the best path, then no need to continue CDF = eap.CDF; Path = eap.Path; if (Math.Abs(CDF - Efficiency_UB) < 0.001) { return true; } } return false; }
// Dobule Point Crossover private void DoublePointCrossover(int split_1_F, int split_1_M, List<Point> Father, List<Point> Mother, int split_2_F, int split_2_M, EAPath Son, EAPath Daughter) { Son.Path.AddRange(Father.GetRange(0, split_1_F)); Son.Path.AddRange(Mother.GetRange(split_1_M, split_2_M - split_1_M)); Son.Path.AddRange(Father.GetRange(split_2_F, Father.Count() - split_2_F)); Daughter.Path.AddRange(Mother.GetRange(0, split_1_M)); Daughter.Path.AddRange(Father.GetRange(split_1_F, split_2_F - split_1_F)); Daughter.Path.AddRange(Mother.GetRange(split_2_M, Mother.Count() - split_2_M)); }
// Crossover based on replacement rate private void Crossover() { // Generate remaining quota of the population by crossover (Divide by 2 because I am generating 2 children each time) for (int k = 0; k < Convert.ToInt16(ProjectConstants.EA_ReplacementRate * ProjectConstants.EA_Population / 2); k++) { // Find father and good mother int split_1_F, split_1_M; List<Point> Father, Mother; if (!FindFatherMother(out split_1_F, out split_1_M, out Father, out Mother)) { // Cleaning up Father = null; Mother = null; // Did not find a good Mother k--; continue; } // Found a good mother that has the node // See if father and mother have second common node // And perform crossover int split_2_F = -1; int split_2_M = -1; EAPath Son = new EAPath(); EAPath Daughter = new EAPath(); bool blnTwoCommonNodes = FindSecondCommonNode(split_1_F, split_1_M, Father, Mother, ref split_2_F, ref split_2_M); if (blnTwoCommonNodes) { DoublePointCrossover(split_1_F, split_1_M, Father, Mother, split_2_F, split_2_M, Son, Daughter); } else { SinglePointCrossover(split_1_F, split_1_M, Father, Mother, Son, Daughter); } // Make sure there's no flying backward for non-copter if (curRequest.VehicleType != UAVType.Copter) { bool blnGoodCrossover = GoodCrossover(split_1_F, split_1_M, split_2_F, split_2_M, Son, Daughter, blnTwoCommonNodes); if (!blnGoodCrossover) { // Cleaning up Father = null; Mother = null; Son = null; Daughter = null; // Try again k--; continue; } } // Make sure they still fly all the way. // Now both children are valid paths, let's truncate or extend so they all have length T+1; // After crossover, if Son or Daughter becomes too long, truncate EAPath ShorterPath = new EAPath(); EAPath LongerPath = new EAPath(); TruncateLongerPath(Son, Daughter, ref ShorterPath, ref LongerPath); if (LongerPath.Path.Count == 0) { // Both Son and Daughter have right length. Move on! NewGeneration.Add(Son); NewGeneration.Add(Daughter); continue; } // After crossover, if Son or Daughter becomes too short, // probablistically randomly pick another path and crossover again. // This time only keep the longer one and then truncate. EAPath OldLongerPath = LongerPath; int index1 = -1; Father = ShorterPath.Path; if (!FindMother(index1, Father, out split_1_F, out split_1_M, out Mother)) { // Cleaning up Father = null; Mother = null; // Did not find a good Mother k--; continue; } // Found a good mother that has the node Son = new EAPath(); Daughter = new EAPath(); SinglePointCrossover(split_1_F, split_1_M, Father, Mother, Son, Daughter); bool blnSonLonger = TruncateLongerPath(Son, Daughter, ref ShorterPath, ref LongerPath); EAPath NewLongerPath = LongerPath; // Make sure there's no flying backward for non-copter if (curRequest.VehicleType != UAVType.Copter) { // Only worry about LongerPath if (!blnSonLonger) { split_1_F = split_1_M; Son = Daughter; } bool blnGoodCrossover = GoodCrossover(split_1_F, split_1_F, 0, 0, Son, Son, false); if (!blnGoodCrossover) { // Cleaning up Father = null; Mother = null; Son = null; Daughter = null; LongerPath = null; ShorterPath = null; OldLongerPath = null; NewLongerPath = null; // Try again k--; continue; } } // Add new paths to new generation NewGeneration.Add(OldLongerPath); NewGeneration.Add(NewLongerPath); // Cleaning up Father = null; Mother = null; Son = null; Daughter = null; LongerPath = null; ShorterPath = null; OldLongerPath = null; NewLongerPath = null; } }
// Simply create n copies to save time. private static void CreateEAPathCopies(List<EAPath> AllPaths, int n) { for (int i = 0; i < n; i++) { // Create new EAPath EAPath eap = new EAPath(); eap.CDF = AllPaths[AllPaths.Count - 1].CDF; eap.Path.AddRange(AllPaths[AllPaths.Count - 1].Path); // Add EAPath to population AllPaths.Add(eap); } }
// Check if the crossover is valid for non-copter (no flying backwards) private bool ValidCrossover(int split_point, EAPath Son, int i) { if (split_point != -1 && Son.Path.Count - 1 > split_point && split_point > 1) { if (!ValidMove(Son.Path[split_point - i], Son.Path[split_point - i + 1], Son.Path[split_point - i + 2])) { return false; } } return true; }
// Truncate longer path and identify who is who private bool TruncateLongerPath(EAPath Son, EAPath Daughter, ref EAPath ShorterPath, ref EAPath LongerPath) { if (Son.Path.Count > curRequest.T + 1) { Son.Path.RemoveRange(curRequest.T + 1, Son.Path.Count - (curRequest.T + 1)); LongerPath = Son; ShorterPath = Daughter; return true; } if (Daughter.Path.Count > curRequest.T + 1) { Daughter.Path.RemoveRange(curRequest.T + 1, Daughter.Path.Count - (curRequest.T + 1)); LongerPath = Daughter; ShorterPath = Son; return false; } return true; }