It all started one summer evening, while reading the book of evolutionary biologist Richard Dawkins "God as an illusion." This book is about religion, faith, and atheism, but the author briefly refers to another book, The Selfish Gene, and introduces the concept of the same name. For a long time, I was fascinated by the elegance of genetic algorithms. And now, a month later, once again trying to come up with some mini-project, it suddenly dawned on me - what if, with the help of genetic algorithms, to simulate evolution and see what will evolve. The task is difficult and at this stage of development of IT, I think, unsolvable, so I had to do something simpler. Namely, test the hypothesis of the selfish gene. Interested, please under the cat ...public class World { public readonly List<Creature>[] Species = new List<Creature>[8]; public void Run(int generations) { for (int i = 0; i < generations; i++, this.age = this.Age + 1) { this.SelectBest(); this.MakeChildren(); this.Mutate(); Debug.Print("Age: {0}", i); } } private void SelectBest() { var allCreatures = new List<Creature>(this.Species.Sum(kind => kind.Count)); allCreatures.AddRange(this.Species.SelectMany(kind => kind)); allCreatures = allCreatures.OrderByDescending(creature => creature.SummaryStrength).Take(allCreatures.Count >> 1).ToList(); for (int i = 0; i < this.Species.Length; i++) { this.Species[i].ForEach(creature => creature.BreakRedundantConnections()); this.Species[i].Clear(); this.Species[i].AddRange(allCreatures.Where(creature => creature.IdOfSpecies == i)); } } private void MakeChildren() { Parallel.For( 0, this.Species.Length, i => { var temp = new List<Creature>(this.Species[i].Count << 1); // Random parents (of same species) - for supporting different genes this.Species[i].Shuffle(); Random rnd = RandomProvider.GetThreadRandom(); for (int j = 1; j < this.Species[i].Count; j += 2) { double value = rnd.NextDouble(); if (value < 0.33) { temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); } else if (value < 0.665) { temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); } else { temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); temp.Add(new Creature(this.Species[i][j - 1], this.Species[i][j])); } } this.Species[i].ForEach(creature => creature.BreakRedundantConnections()); this.Species[i].Clear(); this.Species[i] = temp; }); } private void Mutate() { Parallel.ForEach(this.Species, list => list.ForEach(creature => creature.Mutate())); } } public enum Gene : byte { SelfishGene = 1, AltruisticGene = 2, CreatureLevelGene = 4 } public enum Relation { Child, BrotherOrSister, GrandChild, NephewOrNiece, Cousin } public class Creature { private const int GeneStrength = 128; private readonly Gene[] genes = new Gene[128]; private readonly List<Creature> childs = new List<Creature>(8); private Creature mother; private Creature father; public Creature(int idOfSpecies, World world) { Contract.Requires<ArgumentNullException>(world != null); Contract.Ensures(this.IdOfSpecies == idOfSpecies); this.IdOfSpecies = idOfSpecies; this.world = world; for (int i = 0; i < this.genes.Length; i++) { this.genes[i] = EnumHelper.CreateRandomGene(); } } public Creature(Creature mommy, Creature daddy) { Debug.Assert(mommy.IdOfSpecies == daddy.IdOfSpecies, "Interspecies relation are FORBIDDEN!!!"); this.mother = mommy; this.father = daddy; mommy.childs.Add(this); daddy.childs.Add(this); this.world = mommy.world; this.IdOfSpecies = mommy.IdOfSpecies; for (int i = 0; i < this.genes.Length; i++) { this.genes[i] = EnumHelper.ChooseRandomGene(mommy.genes[i], daddy.genes[i]); } } public int SummaryStrength { get { double sum = 0.0; World world = this.world; string cacheKey = $"AltruisticGenesOutStrength{this.IdOfSpecies}"; object cachedValue = Cache.Get(cacheKey, world.Age); if (cachedValue != null) { sum = (double)cachedValue; } else { for (int i = 0; i < world.Species[this.IdOfSpecies].Count; i++) { if (world.Species[this.IdOfSpecies][i] != this) { sum += world.Species[this.IdOfSpecies][i].AltruisticGenesOutStrength; } } Cache.Put(cacheKey, world.Age, sum); } return this.ThisCreatureGenesStrength + (int)sum + (int)this.HelpFromRelations; } } private int ThisCreatureGenesStrength => this.genes.Sum(g => g == Gene.CreatureLevelGene ? GeneStrength : GeneStrength >> 1); private double AltruisticGenesOutStrength { get { int sum = 0; for (int i = 0; i < this.genes.Length; i++) { Gene gene = this.genes[i]; if (gene == Gene.AltruisticGene) { sum += GeneStrength >> 1; } } return (double)sum / (this.world.Species[this.IdOfSpecies].Count - 1); } } private double HelpFromRelations { get { Creature mommy = this.mother; Creature daddy = this.father; if (mommy == null) { return 0; } if (mommy.mother == null) { return mommy.GetSelfishGenesOutStrength(Relation.Child) + daddy.GetSelfishGenesOutStrength(Relation.Child) + mommy.childs.Sum( brother => brother == this ? 0 : brother.GetSelfishGenesOutStrength(Relation.BrotherOrSister)); } return mommy.GetSelfishGenesOutStrength(Relation.Child) + daddy.GetSelfishGenesOutStrength(Relation.Child) + mommy.childs.Sum( brother => brother == this ? 0 : brother.GetSelfishGenesOutStrength(Relation.BrotherOrSister)) + mommy.mother.GetSelfishGenesOutStrength(Relation.GrandChild) + mommy.father.GetSelfishGenesOutStrength(Relation.GrandChild) + daddy.mother.GetSelfishGenesOutStrength(Relation.GrandChild) + daddy.father.GetSelfishGenesOutStrength(Relation.GrandChild) + mommy.mother.childs.Sum( aunt => aunt == mommy ? 0 : aunt.GetSelfishGenesOutStrength(Relation.NephewOrNiece)) + daddy.mother.childs.Sum( uncle => uncle == daddy ? 0 : uncle.GetSelfishGenesOutStrength(Relation.NephewOrNiece)) + mommy.mother.childs.Sum( aunt => aunt == mommy ? 0 : aunt.childs.Sum(cousin => cousin.GetSelfishGenesOutStrength(Relation.Cousin))) + daddy.mother.childs.Sum( uncle => uncle == daddy ? 0 : uncle.childs.Sum(cousin => cousin.GetSelfishGenesOutStrength(Relation.Cousin))); } } public void Mutate() { // Tries to change 6 genes with 50% probability int length = this.genes.Length; int rnd = RandomProvider.GetThreadRandom().Next(length << 1); int limit = Math.Min(length, rnd + 6); for (; rnd < limit; rnd++) { this.genes[rnd] = EnumHelper.CreateRandomGene(); } } public void BreakRedundantConnections() { Creature mommy = this.mother; Creature daddy = this.father; if (mommy?.mother?.mother != null) { mommy.mother.mother?.childs.Clear(); mommy.mother.mother = null; mommy.mother.father?.childs.Clear(); mommy.mother.father = null; mommy.father.mother?.childs.Clear(); mommy.father.mother = null; mommy.father.father?.childs.Clear(); mommy.father.father = null; daddy.mother.mother?.childs.Clear(); daddy.mother.mother = null; daddy.mother.father?.childs.Clear(); daddy.mother.father = null; daddy.father.mother?.childs.Clear(); daddy.father.mother = null; daddy.father.father?.childs.Clear(); daddy.father.father = null; } } private double GetSelfishGenesOutStrength(Relation whoAreYou) { Creature mommy = this.mother; Creature daddy = this.father; int summarySelfishStrength = this.genes.Sum(g => g == Gene.SelfishGene ? GeneStrength >> 1 : 0); switch (whoAreYou) { case Relation.Child: return summarySelfishStrength / this.childs.Count * 30.78; case Relation.BrotherOrSister: Debug.Assert(mommy.childs.Count > 1, "LIER! He is not our brother!"); return summarySelfishStrength / (mommy.childs.Count - 1) * 30.78; case Relation.GrandChild: return summarySelfishStrength / this.childs.Sum(creature => creature.childs.Count) * 15.38; case Relation.NephewOrNiece: Debug.Assert(mommy.childs.Count > 1, "LIER! We don't have any brothers!"); return summarySelfishStrength / mommy.childs.Sum(brother => brother == this ? 0 : brother.childs.Count) * 15.38; case Relation.Cousin: return summarySelfishStrength / (mommy.mother.childs.Sum(aunt => aunt == mommy ? 0 : aunt.childs.Count) + daddy.mother.childs.Sum(uncle => uncle == daddy ? 0 : uncle.childs.Count)) * 7.68; default: throw new NotImplementedException("Unknown enum value"); } } } 
Source: https://habr.com/ru/post/267399/
All Articles