I Can't Believe That Worked

Code and Ideas, minus the profanity (the one language all developers know)

June 2009 - Posts

Genetic Algorithm -- Add Ur Own Func :)

Hi again,

I was a little bored this weekend and needed to add in some GA functionality to a side project. I felt like it would be best to create a simple executer to deal with the iterative behavior of a genetic algorithm. The executer take in funcs provided by the consumer and executes based on a simple iterative model.

I've included a zip of the solution with an example of usage within the accompanying test project.

Below is what I came up with. Cheers!

Code:

    8 #region Dependencies

    9 

   10 using System;

   11 using System.Collections.Generic;

   12 using System.Diagnostics;

   13 using System.Linq;

   14 

   15 #endregion

   16 

   17 namespace GA

   18 {

   19     /// <summary>

   20     /// GeneticAlgorithm runs a genetic algorithm based on an initial population, fitness func, crossover func,

   21     /// optional mutation function, and tollerance

   22     /// </summary>

   23     /// <typeparam name="T">Type to perform the algorithm against</typeparam>

   24     public class GeneticAlgorithm<T>

   25     {

   26         private readonly Func<IEnumerable<FitnessComposite<T>>, IEnumerable<T>> _crossoverFunction;

   27         private readonly Func<IEnumerable<T>, IEnumerable<FitnessComposite<T>>> _fitnessFunction;

   28         private readonly Func<IEnumerable<T>, IEnumerable<T>> _mutationFunction;

   29         private readonly double _tollerance;

   30         private IEnumerable<T> _population;

   31 

   32         /// <summary>

   33         ///

   34         /// </summary>

   35         /// <param name="population">initial population</param>

   36         /// <param name="fitnessFunction">function for calculating fitness</param>

   37         /// <param name="crossoverFunction">breeding fuction</param>

   38         /// <param name="mutationFunction">mutation function (optional, use null if not needed)</param>

   39         /// <param name="tollerance">fitness tollernance</param>

   40         public GeneticAlgorithm(IEnumerable<T> population,

   41                                 Func<IEnumerable<T>, IEnumerable<FitnessComposite<T>>> fitnessFunction,

   42                                 Func<IEnumerable<FitnessComposite<T>>, IEnumerable<T>> crossoverFunction,

   43                                 Func<IEnumerable<T>, IEnumerable<T>> mutationFunction,

   44                                 double tollerance)

   45         {

   46             _population = population;

   47             _fitnessFunction = fitnessFunction;

   48             _crossoverFunction = crossoverFunction;

   49             _mutationFunction = mutationFunction;

   50             _tollerance = tollerance;

   51         }

   52 

   53         /// <summary>

   54         /// Max number of results to return

   55         /// </summary>

   56         public int? MaxResults { get; set; }

   57 

   58         /// <summary>

   59         /// Max time the algorithm can run

   60         /// </summary>

   61         public TimeSpan? TimeOut { get; set; }

   62 

   63         /// <summary>

   64         /// Result of the algorithm

   65         /// </summary>

   66         public IEnumerable<FitnessComposite<T>> Results { get; private set; }

   67 

   68         /// <summary>

   69         /// Number of generations

   70         /// </summary>

   71         public int Generations { get; private set; }

   72 

   73         /// <summary>

   74         /// Has the algorithm reach the finish criteria (either time has expired, or the tollerance has been reached)

   75         /// </summary>

   76         public bool IsDone { get; private set; }

   77 

   78         /// <summary>

   79         /// The evolving population

   80         /// </summary>

   81         public IEnumerable<T> Population

   82         {

   83             get { return _population; }

   84         }

   85 

   86         /// <summary>

   87         /// Run the algorithm until complete and perform the doneAction at completion

   88         /// </summary>

   89         /// <param name="doneAction">action to be performed when the algorithm time has expired or tollerance has been reached</param>

   90         public void Run(Action<IEnumerable<FitnessComposite<T>>> doneAction)

   91         {

   92             var executer = new Executer(_population)

   93                                {

   94                                    BreedingFunc = GetBreedingFunc(),

   95                                    FitnessFunc = _fitnessFunction,

   96                                };

   97 

   98             if (TimeOut.HasValue)

   99             {

  100                 var timer = new Stopwatch();

  101                 timer.Start();

  102                 executer.FinishCriteria = fitnessItems => IsFitnessReached(fitnessItems) || timer.Elapsed > TimeOut;

  103                 InternalRun(executer, doneAction);

  104                 timer.Stop();

  105             }

  106             else

  107             {

  108                 executer.FinishCriteria = IsFitnessReached;

  109                 InternalRun(executer, doneAction);

  110             }

  111         }

  112 

  113         private void InternalRun(Executer executer, Action<IEnumerable<FitnessComposite<T>>> doneAction)

  114         {

  115             while (executer.Run())

  116             {

  117                 _population = executer.Population;

  118                 Generations++;

  119             }

  120 

  121             IsDone = executer.IsDone;

  122             Results = executer.Results.Where(FitnessIsLessThanOrEqualToTollerance);

  123             if (MaxResults.HasValue && Results.Count() > MaxResults.Value)

  124                 Results = Results.Take(MaxResults.Value);

  125 

  126             doneAction(Results);

  127         }

  128 

  129         private Func<IEnumerable<FitnessComposite<T>>, IEnumerable<T>> GetBreedingFunc()

  130         {

  131             return _mutationFunction != null

  132                        ? i => _mutationFunction(_crossoverFunction(i))

  133                        : _crossoverFunction;

  134         }

  135 

  136         private bool IsFitnessReached(IEnumerable<FitnessComposite<T>> fitnessComposites)

  137         {

  138             return FitnessIsLessThanOrEqualToTollerance(GetBestFitness(fitnessComposites));

  139         }

  140 

  141         private FitnessComposite<T> GetBestFitness(IEnumerable<FitnessComposite<T>> fitnessComposites)

  142         {

  143             return fitnessComposites.OrderBy(i => i.Fitness).First();

  144         }

  145 

  146         private bool FitnessIsLessThanOrEqualToTollerance(FitnessComposite<T> ratedObject)

  147         {

  148             return ratedObject.Fitness <= _tollerance;

  149         }

  150 

  151         #region Nested type: Executer

  152 

  153         private class Executer

  154         {

  155             private IEnumerable<T> _internalPopulation;

  156 

  157             public Executer(IEnumerable<T> initialPopulation)

  158             {

  159                 _internalPopulation = initialPopulation;

  160             }

  161 

  162             public bool IsDone { get; private set; }

  163             public Func<IEnumerable<FitnessComposite<T>>, bool> FinishCriteria { get; set; }

  164             public Func<IEnumerable<T>, IEnumerable<FitnessComposite<T>>> FitnessFunc { get; set; }

  165             public Func<IEnumerable<FitnessComposite<T>>, IEnumerable<T>> BreedingFunc { get; set; }

  166             public IEnumerable<T> Population { get; private set; }

  167             public IEnumerable<FitnessComposite<T>> Results { get; private set; }

  168 

  169             public bool Run()

  170             {

  171                 var fitnessComposites = FitnessFunc(_internalPopulation);

  172                 IsDone = FinishCriteria(fitnessComposites);

  173                 if (!IsDone)

  174                     _internalPopulation = BreedingFunc(fitnessComposites);

  175                 else

  176                     Results = fitnessComposites;

  177                 Population = _internalPopulation;

  178                 return !IsDone;

  179             }

  180         }

  181 

  182         #endregion

  183     }

  184 }

Twitter: David Justice

Download the Code

.Net 4.0 Reflection vs. Dynamics vs. Property Setting With Times

 

Hello All,

 

Today I found my self hanging out after a sprint review with my partner in crime Kevin Rohling.  TFS was down (not tfs's fault, but some other freak accident...) and I hadn't installed VS 2010 yet, so it seemed like the perfect time to do such things. I got everything up and running, and Kevin and I got into a discussion about Dynamics & performance. We made a quick lunch bet on which is faster, reflection or dynamics for simply setting a property. I figured reflection would be quicker, while Kevin thought dynamics would be faster. Well, I owe him lunch now. The code is below.

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace ConsoleApplication1

{

    class Program

    {

        static void Main(string[] args)

        {

            var nTimes = 1000000;

            var value = "Hello World";

            var myTestType = new MyTestType();

            DateTime start, end;

            var property = typeof(MyTestType).GetProperty("MyDynamicProperty");

 

            start = DateTime.Now;

            for (var i = 0; i < nTimes; i++)

            {

                //var property = typeof(MyTestType).GetProperty("MyDynamicProperty");

                property.SetValue(myTestType, value, null);

            }

            end = DateTime.Now;

            Console.WriteLine(end.Subtract(start).ToString());

 

            dynamic myTestType2 = new MyTestType();

            start = DateTime.Now;

            for (int i = 0; i < nTimes; i++)

            {

                myTestType2.MyDynamicProperty = value;

            }

            end = DateTime.Now;

            Console.WriteLine(end.Subtract(start).ToString());

 

            var myTestType3 = new MyTestType();

            start = DateTime.Now;

            for (int i = 0; i < nTimes; i++)

            {

                myTestType3.MyDynamicProperty = value;

            }

            end = DateTime.Now;

            Console.WriteLine(end.Subtract(start).ToString());

 

            Console.ReadLine();

        }

 

        public class MyTestType

        {

            public string MyDynamicProperty { get; set; }

        }

    }

}

 

Results:

Reflection: 00:00:19.8581040

Dynamics: 00:00:00.6054300

Setting a property plain and simple: 00:00:00.0166005

 

Kevin was right by a long shot!! Who would have guessed that dynamics would be so fast. I'm quite impressed, and tip my hat to the guys that cooked that up! Cheers fellas, but thanks a lot for making my buy lunch...

 

On a side note: Congrats to Kevin Rohling on his winning new CloudApp() with his submission of www.myimpulselive.com!  Check out the app. It's pretty darn slick!