private void RecalculateFitness(Representation reference)
 {
     // Recalculates fitness of members based on similarity criteria
     double weight = 0.4;
     foreach (Representation member in currentPopulation)
     {
         int distance = StaticOperations.TotalDistanceBetweenPaths(reference, member);
         // The higher the distance, the better 
         double newFitness = member.Fitness * (weight + (1 - weight) * distance);
         member.CombinedFitness = newFitness;
     }
 }
        public List <Representation> DuplicationElimination(int mutationAttempts,
                                                            int similarMemberCountThreshold, int similarityThreshold)
        {
            // New population will consist of
            // a) elite ten percent of unique old members
            // b) similar descendants will be repeatadly mutated to achieve higher chance of
            // keeping multiple candidates

            // Choose ten percent of unique members
            List <Representation> eliteMembers = UniqueEliteSelection(oldGeneration.Count / 10 < 6 ? 6 : oldGeneration.Count / 10);
            // Test all descendants
            List <Representation> survivingDescendants = new List <Representation>();

            Decoder    decoder    = new Decoder();
            Evaluation evaluation = new Evaluation();

            for (int i = 0; i < descendants.Count; i++)
            {
                Representation descendant   = descendants[i];
                double         startFitness = descendant.Fitness;
                List <double>  distances    = new List <double>();
                foreach (Representation oldMember in oldGeneration)
                {
                    distances.Add(StaticOperations.TotalDistanceBetweenPaths(descendant, oldMember));
                }

                int similarCount = distances.Count(item => item <= similarityThreshold);
                if (similarCount > similarMemberCountThreshold)
                {
                    GeneticOperator geneticOperator = new GeneticOperator();
                    int             attempts        = 0;
                    while (similarCount > similarMemberCountThreshold && attempts < mutationAttempts)
                    {
                        descendant = geneticOperator.MutateMember(descendant);

                        distances.Clear();
                        foreach (Representation oldMember in oldGeneration)
                        {
                            distances.Add(StaticOperations.TotalDistanceBetweenPaths(descendant, oldMember));
                        }

                        similarCount = distances.Count(item => item <= similarityThreshold);
                        attempts++;

                        // Prevents repetitive mutation to have an aspiring solution stuck at lower fitness values
                        if (IsUnique(descendant) && evaluation.EvaluatePath(decoder.DecodeRepresentation(descendant)) > startFitness)
                        {
                            break;
                        }
                    }
                    survivingDescendants.Add(descendant);
                }
                else
                {
                    survivingDescendants.Add(descendant);
                }
            }

            // Some members were mutated and their fitness is unknown
            foreach (Representation descendant in survivingDescendants)
            {
                if (descendant.Fitness == 0)
                {
                    descendant.Fitness = evaluation.EvaluatePath(decoder.DecodeRepresentation(descendant));
                }
            }
            survivingDescendants.OrderByDescending(item => item.Fitness);

            eliteMembers.AddRange(survivingDescendants.Take(nextGenerationCount - eliteMembers.Count));

            return(eliteMembers);
        }
        public List <Representation> NextGeneration()
        {
            // New generation will consist of both old and new members
            // Genetic operators generate as many descendants as there are parents
            // Every descendant will compete against a small selection of old generation
            // From that selection, the most similar member is chosen and competes against the descendant
            // Winner remains in population
            List <Representation> newGeneration = StaticOperations.CloneList(oldGeneration);
            List <Representation> eliteMembers  = UniqueEliteSelection(oldGeneration.Count / 10 < 6 ? 6 : oldGeneration.Count / 10);

            foreach (Representation representation in eliteMembers)
            {
                Representation member = newGeneration.Find(item => item.Values.SequenceEqual(representation.Values));
                newGeneration.Remove(member);
            }
            List <Representation> survivingDescendatns = new List <Representation>();

            descendants.Shuffle();
            descendants = descendants.Skip(eliteMembers.Count).ToList();
            Random random = new Random();

            foreach (Representation descendant in descendants)
            {
                // Generate random selection of old members
                int   sampleCount   = random.Next(3, 7);
                int[] sampleIndices = new int[sampleCount];
                for (int i = 0; i < sampleCount; i++)
                {
                    sampleIndices[i] = random.Next(0, newGeneration.Count);
                }
                List <Representation> sampleMembers = new List <Representation>();
                for (int i = 0; i < sampleCount; i++)
                {
                    sampleMembers.Add(newGeneration[sampleIndices[i]]);
                }

                // Calculate, which of the selected members is more similar to current member
                int[] distancesField = new int[sampleCount];
                for (int i = 0; i < sampleMembers.Count; i++)
                {
                    distancesField[i] = StaticOperations.TotalDistanceBetweenPaths(descendant, sampleMembers[i]);
                }
                int minDistanceIndex = 0;
                for (int i = 0; i < distancesField.Length; i++)
                {
                    if (distancesField[minDistanceIndex] < distancesField[i])
                    {
                        minDistanceIndex = i;
                    }
                }

                // Stochastic competition
                // Descendant and old member fight in stochastic probabilistic tournament
                // based on their fitness
                int selectingNumber = random.Next(0, (int)(descendant.Fitness + sampleMembers[minDistanceIndex].Fitness));
                if (selectingNumber <= (int)descendant.Fitness)
                {
                    survivingDescendatns.Add(descendant);
                    newGeneration.Remove(sampleMembers[minDistanceIndex]);
                }

                // Compare fitness of descendant and calculated similar member
                // Winner goes into new generation
                //if (descendant.Fitness > sampleMembers[minDistanceIndex].Fitness)
                //{
                //    survivingDescendatns.Add(descendant);
                //    newGeneration.Remove(sampleMembers[minDistanceIndex]);
                //}
            }

            // New generation consists of old generation members that won their duels and
            // descendants that eliminated losing old generation members
            newGeneration.AddRange(survivingDescendatns);
            newGeneration.AddRange(eliteMembers);

            return(newGeneration);
        }