public void RunAll(EAConfig config, Stock stock, IEnumerable <ShapeTemplate> shapes) { logFileData = new List <List <Tuple <int, List <double> > > >(); LogFileText = ""; for (int r = 0; r < config.NumRuns; r++) { Console.WriteLine("Starting Run {0}", r); Run(config, stock, shapes); } // Log File using (var logFile = new StreamWriter(config.LogFile, false)) { int runCounter = 0; logFile.WriteLine("[Config Log (seed = {0})]", config.Seed); logFile.WriteLine(File.ReadAllText(config.ConfigFile)); logFile.WriteLine("\n\n[Results Log]"); foreach (var runData in logFileData) { logFile.WriteLine("\n[Run {0}]", runCounter); foreach (var data in runData) { logFile.WriteLine("{0}\t{1}", data.Item1, String.Join("\t", data.Item2)); } runCounter += 1; } } // Solution File var solutions = new List <Dictionary <ShapeTemplate, ShapeCut> >(); foreach (var bestSolution in BestPopulation) { var solutionDict = new Dictionary <ShapeTemplate, ShapeCut>(); solutions.Add(solutionDict); foreach (var shape in bestSolution.Phenotype()) { solutionDict[shape.Template] = shape; } } using (var solutionFile = new StreamWriter(config.SolutionFile, false)) { solutionFile.WriteLine(solutions.Count()); foreach (var solutionDict in solutions) { solutionFile.WriteLine("\n[Solution]\n"); foreach (var shapeTempl in shapes) { var shape = solutionDict[shapeTempl]; solutionFile.WriteLine("{0},{1},{2}", shape.Origin.X, shape.Origin.Y, (int)shape.Rotation); } } } }
public static EAConfig FromArguments(string[] args) { var options = new EAConfig(); options.ConfigFile = args[0]; options.ProblemFile = args[1]; options.SolutionFile = args[2]; options.LogFile = args[3]; options.Seed = Convert.ToInt32(args[4]); options.NumRuns = Convert.ToInt32(args[5]); options.NumParents = Convert.ToInt32(args[6]); options.NumOffspring = Convert.ToInt32(args[7]); options.SolutionInit = args[8]; options.Sharing = Boolean.Parse(args[9]); options.ParentSelection = new ParentSelection(); options.ParentSelection.SelectionWeight = (SelectionWeight)Enum.Parse(typeof(SelectionWeight), args[10]); options.ParentSelection.SelectPool = Convert.ToInt32(args[11]); options.ParentSelection.Replacement = Boolean.Parse(args[12]); options.ParentSelection.RateP = Convert.ToDouble(args[13]); options.ParentSelection.AdaptiveCrossover = Boolean.Parse(args[14]); options.ParentSelection.RateAdjacencyCrossover = Convert.ToDouble(args[15]); options.SurvivalSelection = new SurvivalSelection(); options.SurvivalSelection.SelectionWeight = (SelectionWeight)Enum.Parse(typeof(SelectionWeight), args[16]); options.SurvivalSelection.SelectPool = Convert.ToInt32(args[17]); options.SurvivalSelection.DropParents = Boolean.Parse(args[18]); options.SurvivalSelection.Replacement = Boolean.Parse(args[19]); options.SurvivalSelection.RateP = Convert.ToDouble(args[20]); options.Termination = new Termination(); options.Termination.EvalLimit = Convert.ToInt32(args[21]); options.Termination.GenerationLimit = Convert.ToInt32(args[22]); options.Termination.UnchangedBestLimit = Convert.ToInt32(args[23]); options.Mutations = new OffspringMutation(); options.Mutations.Adaptive = Boolean.Parse(args[24]); options.Mutations.RateCreepRandom = Convert.ToDouble(args[25]); options.Mutations.RateRotateRandom = Convert.ToDouble(args[26]); options.Mutations.RateSlideRandom = Convert.ToDouble(args[27]); options.Fitness = new FitnessEval(); options.Fitness.Length = Boolean.Parse(args[28]); options.Fitness.Width = Boolean.Parse(args[29]); options.Fitness.Cut = Boolean.Parse(args[30]); options.Fitness.Adjacents = Boolean.Parse(args[31]); return(options); }
public static void Main(string[] args) { EAConfig config; try { config = EAConfig.FromArguments(args); } catch (System.FormatException) { Console.WriteLine(String.Join(" ", args)); return; } CmnRandom.InitRandom(config.Seed); var problem = ProblemFile.Parse(config.ProblemFile); new StockCutterRunner().RunAll(config, problem.Item1, problem.Item2); }
public void Run(EAConfig config, Stock stock, IEnumerable <ShapeTemplate> shapes) { var initialSolutions = new List <SolutionGenome>(); if (config.SolutionInit != "" && File.Exists(config.SolutionInit)) { initialSolutions.AddRange(ReadSolutions(config.SolutionInit, shapes.ToList(), stock, config)); } else { initialSolutions.AddRange(Enumerable .Range(initialSolutions.Count(), config.NumParents) .Select(i => GenerateRandomSolution(shapes, stock, config)) ); } int evalCounter = 0; Func <SolutionGenome, List <int> > evaluateSolution = (individual) => { var evals = new List <int>(); if (config.Fitness.Length) { evals.Add(stock.Length - individual.SolutionLength); } if (config.Fitness.Width) { evals.Add(stock.Width - individual.SolutionWidth); } if (config.Fitness.Cut) { var placements = new Dictionary <Point, Gene>(); foreach (var gene in individual.Genes) { foreach (var point in gene.Phenotype().Points) { placements[point] = gene; } } // Maximizing adjacent points is minimizing cuts evals.Add( individual.Genes.Sum(g => { return(g.Phenotype().AdjacentPoints .Where(p => placements.ContainsKey(p)) .Count()); }) ); } if (config.Fitness.Adjacents) { var placements = new Dictionary <Point, Gene>(); foreach (var gene in individual.Genes) { foreach (var point in gene.Phenotype().Points) { placements[point] = gene; } } // Minimize number of shapes that are adjacent to each other, also, keep it positive evals.Add( (individual.Genes.Count() * individual.Genes.Count()) - individual.Genes.Sum(g => { return(new HashSet <Gene>( g.Phenotype().AdjacentPoints .Where(p => placements.ContainsKey(p)) .Select(p => placements[p]) ).Count()); }) ); } return(evals); }; Func <IEnumerable <SolutionGenome>, List <EvalNode <SolutionGenome> > > evaluate = (population) => { evalCounter += population.Count(); var popFits = new Dictionary <SolutionGenome, List <int> >(); foreach (var individual in population) { popFits[individual] = evaluateSolution(individual); } var fittedPopulation = new List <EvalNode <SolutionGenome> >(); var levels = new Dictionary <SolutionGenome, int>(); var dominatedBy = new Dictionary <SolutionGenome, List <SolutionGenome> >(); if (popFits[population.First()].Count() > 1) { foreach (var individual in population) { var fitnessTypes = popFits[individual]; dominatedBy[individual] = new List <SolutionGenome>(); foreach (var dominator in population) { var fitPairs = fitnessTypes .Zip(popFits[dominator], (i, d) => Tuple.Create(i, d)); var ltFits = fitPairs.Where(el => el.Item1 > el.Item2); var rtFits = fitPairs.Where(el => el.Item1 < el.Item2); bool isDominated = ltFits.Count() == 0 && rtFits.Any(); if (isDominated) { dominatedBy[individual].Add(dominator); } } } var unFitted = new List <SolutionGenome>(population); int levelCounter = 1; while (unFitted.Count() > 0) { foreach (var individual in unFitted.ToList()) { bool fit = true; foreach (var dominator in dominatedBy[individual]) { if (!levels.ContainsKey(dominator)) { fit = false; break; } } if (fit) { levels[individual] = -levelCounter; unFitted.Remove(individual); } } levelCounter += 1; } } foreach (var individual in population) { var fitnessTypes = popFits[individual]; int fitness = 0; if (fitnessTypes.Count() == 1) { fitness = fitnessTypes.First(); } else if (fitnessTypes.Count() > 1) { fitness = levels[individual]; } var newFit = new EvalNode <SolutionGenome>(individual, fitness); fittedPopulation.Add(newFit); } if (config.Sharing) { foreach (var eFit in fittedPopulation) { foreach (var nicheFit in fittedPopulation) { eFit.Fitness += (int)Math.Floor(nicheFit.Fitness / Math.Pow(1 + SolutionDistance(eFit.Individual, nicheFit.Individual), 2)); } } } return(fittedPopulation); }; BestPopulation = new List <SolutionGenome>(); int unchangedBest = 0; int generationCounter = 0; Func <IEnumerable <SolutionGenome>, bool> terminate = (population) => { generationCounter += 1; var _evalPopulation = evaluate((new [] { population, BestPopulation }).SelectMany(p => p)) .ToList(); int maxFitness = _evalPopulation.Max(i => i.Fitness); // We need this unique population handling to prevent best pop bloat in moea var uniquePops = new Dictionary <string, EvalNode <SolutionGenome> >(); foreach (var e in _evalPopulation.Where(s => s.Fitness == maxFitness)) { uniquePops[String.Join(",", evaluateSolution(e.Individual))] = e; } var evalPopulation = uniquePops.Values.ToList(); bool isNewBest = true; var bestUniquePops = BestPopulation.ToDictionary(i => String.Join(",", evaluateSolution(i)), i => i); foreach (var newBest in evalPopulation) { if (!bestUniquePops.ContainsKey(String.Join(",", evaluateSolution(newBest.Individual)))) { isNewBest = false; unchangedBest = 0; break; } } BestPopulation = evalPopulation.Select(e => e.Individual).ToList(); if (isNewBest) { unchangedBest += 1; } Console.WriteLine("Evals {0}\tLevels: {1}\tAvg Fitness: {2}\tBest Fitnesss {3}\tMutations: {4:0.000} {5:0.000} {6:0.000}\tCrossover: {7:0.000}", evalCounter, (new HashSet <int>(_evalPopulation.Select(e => e.Fitness))).Count(), String.Join(",", population .Select(s => evaluateSolution(s)) .Aggregate(new List <int> { 0, 0, 0, 0 }, (lhs, rhs) => lhs.Zip(rhs, (l, r) => l + r).ToList()) .Select(total => String.Format("{0:0.000}", total / (double)population.Count())) ), String.Join(",", population .Select(s => evaluateSolution(s)) .Aggregate(new List <int> { 0, 0, 0, 0 }, (lhs, rhs) => lhs.Zip(rhs, (l, r) => Math.Max(l, r)).ToList()) ), population.Sum(p => p.RateCreepRandom) / population.Count(), population.Sum(p => p.RateRotateRandom) / population.Count(), population.Sum(p => p.RateSlideRandom) / population.Count(), population.Sum(p => p.RateAdjacencyCrossover) / population.Count() ); bool evalLimitReached = config.Termination.EvalLimit != 0 && config.Termination.EvalLimit <= evalCounter; bool generationLimitReached = config.Termination.GenerationLimit != 0 && config.Termination.GenerationLimit < generationCounter; bool unchangedBestReached = config.Termination.UnchangedBestLimit != 0 && config.Termination.UnchangedBestLimit < unchangedBest; return(evalLimitReached || generationLimitReached || unchangedBestReached); }; Func <IEnumerable <SolutionGenome>, IEnumerable <SolutionGenome>, IEnumerable <SolutionGenome> > survive; switch (config.SurvivalSelection.SelectionWeight) { case SelectionWeight.Truncate: survive = (parents, offspring) => { return(evaluate( new[] { parents.SkipWhile(s => config.SurvivalSelection.DropParents), offspring } .SelectMany(p => p) ) .OrderByDescending(o => o.Fitness) .Select(o => o.Individual) .Take(parents.Count())); }; break; case SelectionWeight.Random: survive = EASurvivalSelection <SolutionGenome> .CreateTournamentSelector( (kChoices) => kChoices.ToList().ChooseSingle(), evaluate, config.SurvivalSelection.SelectPool, config.SurvivalSelection.Replacement, config.SurvivalSelection.DropParents, config.NumParents ); break; case SelectionWeight.Best: survive = EASurvivalSelection <SolutionGenome> .CreateTournamentSelector( (kChoices) => kChoices.MaxByValue((k) => k.Fitness), evaluate, config.SurvivalSelection.SelectPool, config.SurvivalSelection.Replacement, config.SurvivalSelection.DropParents, config.NumParents ); break; case SelectionWeight.Fitness: survive = EASurvivalSelection <SolutionGenome> .CreateTournamentSelector( (kChoices) => { var totalFitness = kChoices.Sum(k => k.Fitness); var fitPick = CmnRandom.Random.Next(0, totalFitness - 1); return(kChoices.First(k => { fitPick -= k.Fitness; return fitPick <= 0; })); }, evaluate, config.SurvivalSelection.SelectPool, config.SurvivalSelection.Replacement, config.SurvivalSelection.DropParents, config.NumParents ); break; case SelectionWeight.Rank: survive = EASurvivalSelection <SolutionGenome> .CreateTournamentSelector( (kChoices) => kChoices .OrderBy((k) => - k.Fitness) .Select((k, index) => Tuple.Create(k, config.SurvivalSelection.RateP *Math.Pow(1 - config.SurvivalSelection.RateP, index))) .Select(ki => Tuple.Create(ki.Item1, CmnRandom.Random.NextDouble() < ki.Item2)) .OrderBy(kp => !kp.Item2) .First().Item1, evaluate, config.SurvivalSelection.SelectPool, config.SurvivalSelection.Replacement, config.SurvivalSelection.DropParents, config.NumParents ); break; case SelectionWeight.Crowding: survive = EASurvivalSelection <SolutionGenome> .CreateCrowdingSelector( (kChoices) => { return(kChoices .OrderBy((k) => - k.Fitness) .Select((k, index) => Tuple.Create(k, config.SurvivalSelection.RateP *Math.Pow(1 - config.SurvivalSelection.RateP, index))) .Select(ki => Tuple.Create(ki.Item1, CmnRandom.Random.NextDouble() < ki.Item2)) .OrderBy(kp => !kp.Item2) .First().Item1); }, evaluate, SolutionDistance, config.SurvivalSelection.SelectPool, config.NumParents ); break; default: throw new NotImplementedException("Selection weight for survival not found"); } Func <IEnumerable <SolutionGenome>, IEnumerable <SolutionGenome> > breed; switch (config.ParentSelection.SelectionWeight) { case SelectionWeight.None: breed = (population) => { return(Enumerable .Range(0, config.NumOffspring) .Select(i => GenerateRandomSolution(shapes, stock, config))); }; break; case SelectionWeight.Random: breed = EAParentSelection <SolutionGenome> .CreateTournamentSelector( SolutionGenome.GetParentBreeder(stock), (kChoices) => kChoices.ToList().ChooseSingle(), evaluate, config.ParentSelection.SelectPool, config.ParentSelection.Replacement, config.NumOffspring ); break; case SelectionWeight.Best: breed = EAParentSelection <SolutionGenome> .CreateTournamentSelector( SolutionGenome.GetParentBreeder(stock), (kChoices) => kChoices.MaxByValue((k) => k.Fitness), evaluate, config.ParentSelection.SelectPool, config.ParentSelection.Replacement, config.NumOffspring ); break; case SelectionWeight.Fitness: breed = EAParentSelection <SolutionGenome> .CreateTournamentSelector( SolutionGenome.GetParentBreeder(stock), (kChoices) => { var totalFitness = kChoices.Sum(k => k.Fitness); var fitPick = CmnRandom.Random.Next(0, totalFitness - 1); return(kChoices.First(k => { fitPick -= k.Fitness; return fitPick <= 0; })); }, evaluate, config.ParentSelection.SelectPool, config.ParentSelection.Replacement, config.NumOffspring ); break; case SelectionWeight.Rank: breed = EAParentSelection <SolutionGenome> .CreateTournamentSelector( SolutionGenome.GetParentBreeder(stock), (kChoices) => kChoices .OrderBy((k) => - k.Fitness) .Select((k, index) => Tuple.Create(k, config.ParentSelection.RateP *Math.Pow(1 - config.ParentSelection.RateP, index))) .Select(ki => Tuple.Create(ki.Item1, CmnRandom.Random.NextDouble() < ki.Item2)) .OrderBy(kp => !kp.Item2) .First().Item1, evaluate, config.ParentSelection.SelectPool, config.ParentSelection.Replacement, config.NumOffspring ); break; default: throw new NotImplementedException("Selection weight for parents not handled"); } Action <IEnumerable <SolutionGenome> > mutator = (population) => { foreach (var individual in population) { foreach (var gene in individual.Genes) { if (CmnRandom.Random.NextDouble() < individual.RateCreepRandom) { gene.CreepRandomize(stock.Length); } if (CmnRandom.Random.NextDouble() < individual.RateRotateRandom) { gene.RotateRandomize(); } if (CmnRandom.Random.NextDouble() < individual.RateSlideRandom) { gene.SlideRandomize(stock.Length); } } individual.Repair(stock); } }; var ea = new EvolveSolution <SolutionGenome>( initialSolutions, breed, mutator, survive, terminate ); var newLogData = new List <Tuple <int, List <double> > >(); foreach (var population in ea.Solve()) { var avg = population .Select(s => evaluateSolution(s)) .Aggregate(new List <int> { 0, 0, 0, 0 }, (lhs, rhs) => lhs.Zip(rhs, (l, r) => l + r).ToList()) .Select(total => total / (double)population.Count()); var best = population .Select(s => evaluateSolution(s)) .Aggregate(new List <int> { 0, 0, 0, 0 }, (lhs, rhs) => lhs.Zip(rhs, (l, r) => Math.Max(l, r)).ToList()); var avgBest = avg .Zip(best, (a, b) => new List <double>(new double[] { a, b })) .SelectMany(i => i); newLogData.Add(Tuple.Create(evalCounter, avgBest.ToList())); } logFileData.Add(newLogData); }
public static SolutionGenome GenerateRandomSolution(IEnumerable <ShapeTemplate> shapes, Stock stock, EAConfig config) { var solution = SolutionGenome.ConstructRandom(shapes, stock.Length, config); solution.Repair(stock); return(solution); }
public static IEnumerable <SolutionGenome> ReadSolutions(string solutionFile, List <ShapeTemplate> shapes, Stock stock, EAConfig config) { using (var solFile = new StreamReader(solutionFile, false)) { List <Gene> genes = null; int shapeCounter = 0; string line; while ((line = solFile.ReadLine()) != null) { line = line.Trim(); if (line.Contains("[Solution]")) { if (genes != null && genes.Any()) { yield return(SolutionGenome.ConstructConfig(genes, stock.Length, config)); } genes = new List <Gene>(); shapeCounter = 0; } else if (line != "" && genes != null) { var lineData = line.Split(new [] { ',' }).Select(num => Convert.ToInt32(num)).ToList(); var point = new Point(lineData[0], lineData[1]); var rotation = (ClockwiseRotation)(lineData[2]); genes.Add(new Gene(shapes[shapeCounter], point, rotation)); shapeCounter += 1; } } if (genes != null && genes.Any()) { yield return(SolutionGenome.ConstructConfig(genes, stock.Length, config)); } } }