static void Main(string[] args) { int dataLen; int[,] data; int[,] population; int[] fitnessValues; #if BERLIN_DEBUG Debugger.Launch(); #endif Console.CancelKeyPress += (sender, e) => { _running = false; }; ProgramSettings settings = new ProgramSettings(); string error = null; if (!ParseCommandLine(args, settings, ref error)) { Console.WriteLine(error); throw new NullReferenceException(); } using (FileStream stream = new FileStream(settings.DataFile, FileMode.Open, FileAccess.Read, FileShare.Read)) using (StreamReader reader = new StreamReader(stream)) { string header = reader.ReadLine(); dataLen = int.Parse(header); data = new int[dataLen, dataLen]; for (int i = 0; i < dataLen; ++i) { string[] line = reader.ReadLine() .Trim() .Split(' '); for (int j = 0; j <= i; ++j) { int val = int.Parse(line[j]); data[i, j] = val; data[j, i] = val; } } } #if BERLIN_DEBUG /* * NOTE(SpectatorQL): This doesn't catch situations where some wild * combination of nodes gives us the exact same sum, but at least * it provides _some_ means of asserting that a specimen is valid. */ int validationSum = 0; for (int i = 0; i < dataLen; ++i) { validationSum += i; } #endif var bestSpecimen = new BestSpecimen { Nodes = new int[dataLen], Value = int.MaxValue }; int m = settings.PopulationSize; double mutationChance = settings.MutationChance; op_selection Selection = settings.Selection; op_crossover Crossover = settings.Crossover; population = new int[m, dataLen]; fitnessValues = new int[m]; for (int i = 0; i < m; ++i) { for (int j = 0; j < dataLen; ++j) { population[i, j] = j; } for (int j = 0; j < dataLen; ++j) { int swapIdx = _rand.Next(dataLen); int a = population[i, j]; population[i, j] = population[i, swapIdx]; population[i, swapIdx] = a; } } EvaluateFitness(data, population, m, dataLen, fitnessValues); int[] selected = new int[m]; while (Continue()) { Debug_StartTimer(); int[,] newPopulation = new int[m, dataLen]; Selection(selected, fitnessValues, m); for (int i = 0; i < m; i += 2) { int[] parent1 = new int[dataLen]; int[] parent2 = new int[dataLen]; int p1 = selected[i]; int p2 = selected[i + 1]; for (int j = 0; j < dataLen; ++j) { parent1[j] = population[p1, j]; parent2[j] = population[p2, j]; } int midPoint = dataLen / 2; int offset = 0; int leftCut = _rand.Next(offset, midPoint); int rightCut = _rand.Next(midPoint, dataLen - offset); int[] child1 = new int[dataLen]; int[] child2 = new int[dataLen]; Crossover(child1, parent1, parent2, leftCut, rightCut, dataLen); Crossover(child2, parent2, parent1, leftCut, rightCut, dataLen); int range = 100; double d = _rand.Next(range) / (double)range; if (d <= mutationChance) { InversionMutation(child1, dataLen); } d = _rand.Next(range) / (double)range; if (d <= mutationChance) { InversionMutation(child1, dataLen); } #if BERLIN_DEBUG Debug.Assert(IsValidSpecimen(child1, validationSum)); Debug.Assert(IsValidSpecimen(child2, validationSum)); #endif for (int j = 0; j < dataLen; ++j) { newPopulation[i, j] = child1[j]; newPopulation[i + 1, j] = child2[j]; } } population = newPopulation; EvaluateFitness(data, population, m, dataLen, fitnessValues); int bestVal = fitnessValues[0]; int bestValIdx = 0; for (int i = 1; i < m; ++i) { int val = fitnessValues[i]; if (val < bestVal) { bestVal = val; bestValIdx = i; } } if (bestVal < bestSpecimen.Value) { for (int i = 0; i < dataLen; ++i) { bestSpecimen.Nodes[i] = population[bestValIdx, i]; } bestSpecimen.Value = bestVal; PrintOutput(bestSpecimen, dataLen); } Debug_StopTimer(); } Console.WriteLine("Press any key to exit."); }
static bool ParseCommandLine(string[] args, ProgramSettings settings, ref string error) { bool result = false; if ((args != null) || (args.Length != 0)) { string file = args[0]; if (File.Exists(file)) { settings.DataFile = args[0]; bool popSizeParseSuccess = int.TryParse(args[1], out settings.PopulationSize); if (popSizeParseSuccess) { /* * NOTE(SpectatorQL): Enables the use of a dot in run.bat, * instead of the culture-specific decimal point character. */ bool mutationChanceParseSuccess = double.TryParse(args[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out settings.MutationChance); if (mutationChanceParseSuccess) { for (int i = 3; i < args.Length; ++i) { string arg = args[i]; switch (arg) { case "-tournament": { settings.Selection = TournamentSelect; break; } case "-roulette": { settings.Selection = RouletteSelect; break; } case "-PMX": { settings.Crossover = PMXCrossover; break; } case "-OX": { settings.Crossover = OXCrossover; break; } default: { Console.WriteLine("Unrecognized parameter: \"{0}\"", arg); break; } } } if (settings.Selection != null) { if (settings.Crossover != null) { result = true; } else { error = "Error. Invalid crossover parameter."; } } else { error = "Error. Invalid selection parameter."; } } else { error = "Error. Incorrect mutation chance (expected double)"; } } else { error = "Error. Incorrect population size (expected int)."; } } else { error = "Error. File " + file + " not found."; } } else { error = "Error. The program was launched without any parameters."; } return(result); }