Starting with:

 The target string: "METHINKS IT IS LIKE A WEASEL".
 An array of random characters chosen from the set of upper-case letters together with the space, and of the same length as the target string. (Call it the parent).
 A fitness function that computes the ‘closeness’ of its argument to the target string.
 A mutate function that given a string and a mutation rate returns a copy of the string, with some characters probably mutated.
 While the parent is not yet the target:
 copy the parent C times, each time allowing some random probability that another character might be substituted using mutate.
 Assess the fitness of the parent and all the copies to the target and make the most fit string the new parent, discarding the others.
 repeat until the parent converges, (hopefully), to the target.


See also

   Wikipedia entry:   Weasel algorithm.
   Wikipedia entry:   Evolutionary algorithm.

Note: to aid comparison, try and ensure the variables and functions mentioned in the task description appear in solutions



A cursory examination of a few of the solutions reveals that the instructions have not been followed rigorously in some solutions. Specifically,

 While the parent is not yet the target:
 copy the parent C times, each time allowing some random probability that another character might be substituted using mutate.
Note that some of the the solutions given retain characters in the mutated string that are correct in the target string. However, the instruction above does not state to retain any of the characters while performing the mutation. Although some may believe to do so is implied from the use of "converges"

(:* repeat until the parent converges, (hopefully), to the target.

Strictly speaking, the new parent should be selected from the new pool of mutations, and then the new parent used to generate the next set of mutations with parent characters getting retained only by not being mutated. It then becomes possible that the new set of mutations has no member that is fitter than the parent!

As illustration of this error, the code for 8th has the following remark.

Create a new string based on the TOS, changing randomly any characters which
don't already match the target:

NOTE: this has been changed, the 8th version is completely random now

Clearly, this algo will be applying the mutation function only to the parent characters that don't match to the target characters!

To ensure that the new parent is never less fit than the prior parent, both the parent and all of the latest mutations are subjected to the fitness test to select the next parent.




%This class impliments a string that mutates to a target
classdef EvolutionaryAlgorithm
 
    properties
 
        target;
        parent;
        children = {};
        validAlphabet;
 
        %Constants
        numChildrenPerIteration;
        maxIterations;
        mutationRate;
 
    end
 
    methods
 
        %Class constructor
        function family = EvolutionaryAlgorithm(target,mutationRate,numChildren,maxIterations)
 
            family.validAlphabet = char([32 (65:90)]); %Space char and A-Z
            family.target = target;
            family.children = cell(numChildren,1);
            family.numChildrenPerIteration = numChildren;
            family.maxIterations = maxIterations;
            family.mutationRate = mutationRate;
            initialize(family);
 
        end %class constructor
 
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %Helper functions and class get/set functions
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
        %setAlphabet() - sets the valid alphabet for the current instance
        %of the EvolutionaryAlgorithm class.
        function setAlphabet(family,alphabet)
 
            if(ischar(alphabet))
                family.validAlphabet = alphabet;
 
                %Makes change permanent
                assignin('caller',inputname(1),family); 
            else
                error 'New alphabet must be a string or character array';
            end            
 
        end
 
        %setTarget() - sets the target for the current instance
        %of the EvolutionaryAlgorithm class.
        function setTarget(family,target)
 
            if(ischar(target))
                family.target = target;
 
                %Makes change permanent
                assignin('caller',inputname(1),family); 
            else
                error 'New target must be a string or character array';
            end            
 
        end
 
        %setMutationRate() - sets the mutation rate for the current instance
        %of the EvolutionaryAlgorithm class.
        function setMutationRate(family,mutationRate)
 
            if(isnumeric(mutationRate))
                family.mutationRate = mutationRate;
 
                %Makes change permanent
                assignin('caller',inputname(1),family); 
            else
                error 'New mutation rate must be a double precision number';
            end            
 
        end
 
        %setMaxIterations() - sets the maximum number of iterations during
        %evolution for the current instance of the EvolutionaryAlgorithm class.
        function setMaxIterations(family,maxIterations)
 
            if(isnumeric(maxIterations))
                family.maxIterations = maxIterations;
 
                %Makes change permanent
                assignin('caller',inputname(1),family); 
            else
                error 'New maximum amount of iterations must be a double precision number';
            end            
 
        end
 
        %display() - overrides the built-in MATLAB display() function, to
        %display the important class variables
        function display(family)
            disp([sprintf('Target: %s\n',family.target)...
                  sprintf('Parent: %s\n',family.parent)...
                  sprintf('Valid Alphabet: %s\n',family.validAlphabet)...
                  sprintf('Number of Children: %d\n',family.numChildrenPerIteration)...
                  sprintf('Mutation Rate [0,1]: %d\n',family.mutationRate)...
                  sprintf('Maximum Iterations: %d\n',family.maxIterations)]);                 
        end
 
        %disp() - overrides the built-in MATLAB disp() function, to
        %display the important class variables
        function disp(family)
            display(family);
        end
 
        %randAlphabetElement() - Generates a random character from the
        %valid alphabet for the current instance of the class.
        function elements = randAlphabetElements(family,numChars)
 
            %Sample the valid alphabet randomly from the uniform
            %distribution
            N = length(family.validAlphabet);
            choices = ceil(N*rand(1,numChars));
 
            elements = family.validAlphabet(choices);
 
        end
 
        %initialize() - Sets the parent to a random string of length equal
        %to the length of the target
        function parent = initialize(family)
 
            family.parent = randAlphabetElements(family,length(family.target));
            parent = family.parent;
 
            %Makes changes to the instance of EvolutionaryAlgorithm permanent
            assignin('caller',inputname(1),family); 
 
        end %initialize
 
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %Functions required by task specification
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
        %mutate() - generates children from the parent and mutates them
        function mutate(family)
 
            sizeParent = length(family.parent);
 
            %Generate mutatant children sequentially
            for child = (1:family.numChildrenPerIteration)
 
                parentCopy = family.parent;
 
                for charIndex = (1:sizeParent) 
                    if (rand(1) < family.mutationRate)
                        parentCopy(charIndex) = randAlphabetElements(family,1);
                    end
                end
 
                family.children{child} = parentCopy;
 
            end
 
            %Makes changes to the instance of EvolutionaryAlgorithm permanent
            assignin('caller',inputname(1),family);  
 
        end %mutate
 
        %fitness() - Computes the Hamming distance between the target
        %string and the string input as the familyMember argument
        function theFitness = fitness(family,familyMember)
 
            if not(ischar(familyMember))
                error 'The second argument must be a string';
            end
 
            theFitness = sum(family.target == familyMember);
        end
 
        %evolve() - evolves the family until the target is reached or it 
        %exceeds the maximum amount of iterations        
        function [iteration,mostFitFitness] = evolve(family)
 
            iteration = 0;
            mostFitFitness = 0;
            targetFitness = fitness(family,family.target);
 
            disp(['Target fitness is ' num2str(targetFitness)]);
 
            while (mostFitFitness < targetFitness) && (iteration < family.maxIterations)
 
                iteration = iteration + 1;
 
                mutate(family);
 
                parentFitness = fitness(family,family.parent);                
                mostFit = family.parent;
                mostFitFitness = parentFitness;
 
                for child = (1:family.numChildrenPerIteration)
 
                    childFitness = fitness(family,family.children{child});
                    if childFitness > mostFitFitness
                        mostFit = family.children{child};
                        mostFitFitness = childFitness;
                    end
 
                end               
 
                family.parent = mostFit;
                disp([num2str(iteration) ': ' mostFit ' - Fitness: ' num2str(mostFitFitness)]);
 
            end
 
            %Makes changes to the instance of EvolutionaryAlgorithm permanent
            assignin('caller',inputname(1),family);
 
        end %evolve
 
    end %methods
end %classdef