Task: Evolutionary algorithm



C#: using System;
using System.Collections.Generic;
using System.Linq;

static class Program {
    static Random Rng = new Random((int)DateTime.Now.Ticks);

    static char NextCharacter(this Random self) {
        const string AllowedChars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        return AllowedChars[self.Next() % AllowedChars.Length];
    }

    static string NextString(this Random self, int length) {
        return String.Join("", Enumerable.Repeat(' ', length)
            .Select(c => Rng.NextCharacter()));
    }

    static int Fitness(string target, string current) {
        return target.Zip(current, (a, b) => a == b ? 1 : 0).Sum();
    }

    static string Mutate(string current, double rate) {
        return String.Join("", from c in current
               select Rng.NextDouble() <= rate ? Rng.NextCharacter() : c);
    }

    static void Main(string[] args) {
        const string target = "METHINKS IT IS LIKE A WEASEL";
        const int C = 100;
        const double P = 0.05;

        
        string parent = Rng.NextString(target.Length);

        Console.WriteLine("START:       {0,20} fitness: {1}", 
            parent, Fitness(target, parent));
        int i = 0;

        while (parent != target) {
            
            var candidates = Enumerable.Range(0, C + 1)
                .Select(n => n > 0 ? Mutate(parent, P) : parent);

            
            parent = candidates.OrderByDescending(c => Fitness(target, c)).First();

            ++i;
            Console.WriteLine("     #{0,6} {1,20} fitness: {2}", 
                i, parent, Fitness(target, parent));
        }

        Console.WriteLine("END: #{0,6} {1,20}", i, parent);
    }
}









Ada: with Ada.Text_IO;
with Ada.Numerics.Discrete_Random;
with Ada.Numerics.Float_Random;
with Ada.Strings.Fixed;
with Ada.Strings.Maps;

procedure Evolution is

   
   
   subtype DNA_Char is Character range '@' .. 'Z';

   
   subtype DNA_String is String (1 .. 28);

   
   Target : constant DNA_String := "METHINKS@IT@IS@LIKE@A@WEASEL";

   
   
   
   
   function Fitness (DNA : DNA_String) return Natural is
      Result : Natural := 0;
   begin
      for Position in DNA'Range loop
         if DNA (Position) = Target (Position) then
            Result := Result + 1;
         end if;
      end loop;
      return Result;
   end Fitness;

   
   procedure Output_DNA (DNA : DNA_String; Prefix : String := "") is
      use Ada.Strings.Maps;
      Output_Map : Character_Mapping;
   begin
      Output_Map := To_Mapping
        (From => To_Sequence (To_Set (('@'))),
         To   => To_Sequence (To_Set ((' '))));
      Ada.Text_IO.Put (Prefix);
      Ada.Text_IO.Put (Ada.Strings.Fixed.Translate (DNA, Output_Map));
      Ada.Text_IO.Put_Line (", fitness: " & Integer'Image (Fitness (DNA)));
   end Output_DNA;

   
   package Random_Char is new Ada.Numerics.Discrete_Random (DNA_Char);
   DNA_Generator : Random_Char.Generator;

   
   Float_Generator : Ada.Numerics.Float_Random.Generator;

   
   function Mutate (Parent        : DNA_String;
                    Mutation_Rate : Float)
                    return          DNA_String
   is
      Result : DNA_String := Parent;
   begin
      for Position in Result'Range loop
         if Ada.Numerics.Float_Random.Random (Float_Generator) <= Mutation_Rate
         then
            Result (Position) := Random_Char.Random (DNA_Generator);
         end if;
      end loop;
      return Result;
   end Mutate;

   
   
   procedure Evolve (Child_Count   : Positive := 100;
                     Mutation_Rate : Float    := 0.2)
   is
      type Child_Array is array (1 .. Child_Count) of DNA_String;

      
      function Fittest (Candidates : Child_Array) return DNA_String is
         The_Fittest : DNA_String := Candidates (1);
      begin
         for Candidate in Candidates'Range loop
            if Fitness (Candidates (Candidate)) > Fitness (The_Fittest)
            then
               The_Fittest := Candidates (Candidate);
            end if;
         end loop;
         return The_Fittest;
      end Fittest;

      Parent, Next_Parent : DNA_String;
      Children            : Child_Array;
      Loop_Counter        : Positive := 1;
   begin
      
      for Position in Parent'Range loop
         Parent (Position) := Random_Char.Random (DNA_Generator);
      end loop;
      Output_DNA (Parent, "First: ");
      while Parent /= Target loop
         
         for Child in Children'Range loop
            Children (Child) := Mutate (Parent, Mutation_Rate);
         end loop;
         Next_Parent := Fittest (Children);
         
         if Fitness (Next_Parent) > Fitness (Parent) then
            Parent := Next_Parent;
         end if;
         
         if Loop_Counter mod 20 = 0 then
            Output_DNA (Parent, Integer'Image (Loop_Counter) & ": ");
         end if;
         Loop_Counter := Loop_Counter + 1;
      end loop;
      Output_DNA (Parent, "Final (" & Integer'Image (Loop_Counter) & "): ");
   end Evolve;

begin
   
   Random_Char.Reset (DNA_Generator);
   Ada.Numerics.Float_Random.Reset (Float_Generator);
   
   Evolve;
end Evolution;