Click here to Skip to main content
15,895,283 members
Articles / Artificial Intelligence

AForge.NET open source framework

Rate me:
Please Sign up or sign in to vote.
4.97/5 (150 votes)
16 May 2007GPL311 min read 831.3K   48.3K   346  
The article describes an open source C# framework for researchers in the areas of Computer Vision and Artificial Intelligence - image processing, neural networks, genetic algorithms, etc.
// AForge Genetic Library
//
// Copyright � Andrew Kirillov, 2006
// andrew.kirillov@gmail.com
//

namespace AForge.Genetic
{
	using System;
	using AForge;

	/// <summary>
	/// Evaluates fitness of GP chromosomes for time series prediction task
	/// </summary>
	/// 

	/// <summary>
	/// Fitness function for times series prediction problem
	/// </summary>
	/// 
	/// <remarks>The fitness function calculates fitness value of
	/// <see cref="GPTreeChromosome">GP</see> and <see cref="GEPChromosome">GEP</see>
	/// chromosomes with the aim of solving times series prediction problem using
	/// sliding window method. The fitness function's value is computed as:
	/// <code>100.0 / ( error + 1 )</code>
	/// where <b>error</b> equals to the sum of absolute differences between predicted value
	/// and actual future value.
	/// </remarks>
	/// 
	/// <example>The following sample illustrates the usage of <c>TimeSeriesPredictionFitness</c> class:
	/// <code>
	///	// time series to predict
	///	double[] data = new double[13] { 1, 2, 4, 7, 11, 16, 22, 29, 37, 46, 56, 67, 79 };
	///	// constants
	///	double[] constants = new double[10] { 1, 2, 3, 5, 7, 11, 13, 17, 19, 23 };
	///	// create population
	///	Population population = new Population( 100,
	///	new GPTreeChromosome( new SimpleGeneFunction( 5 + constants.Length ) ),
	///	new TimeSeriesPredictionFitness( data, 5, 1, constants ),
	///	new EliteSelection( ) );
	///	// run one epoch of the population
	///	population.RunEpoch( );
	/// </code>
	/// </example>
	/// 
	public class TimeSeriesPredictionFitness : IFitnessFunction
	{
		// time series data
		private double[]	data;
		// varibles
		private double[]	variables;
		// window size
		private int			windowSize;
		// prediction size
		private int			predictionSize;

		/// <summary>
		/// Initializes a new instance of the <see cref="TimeSeriesPredictionFitness"/> class
		/// </summary>
		/// 
		/// <param name="data">Time series to be predicted</param>
		/// <param name="windowSize">Window size - number of past samples used
		/// to predict future value</param>
		/// <param name="predictionSize">Prediction size - number of values to be predicted. These
		/// values are excluded from training set.</param>
		/// <param name="constants">Array of constants to be used as additional
		/// paramters for genetic expression</param>
		/// 
		/// <remarks>The <b>data</b> parameter is a one dimensional array, which defines times
		/// series to predict. The amount of learning samples is equal to the number of samples
		/// in the provided time series, minus window size, minus prediction size.<br /><br />
		/// The <b>predictionSize</b> parameter specifies the amount of samples, which should
		/// be excluded from training set. This set of samples may be used for future verification
		/// of the prediction model.<br /><br />
		/// The <b>constants</b> parameter is an array of constants, which can be used as
		/// additional variables for a genetic expression. The actual amount of variables for
		/// genetic expression equals to the amount of constants plus the window size.
		/// </remarks>
		/// 
		public TimeSeriesPredictionFitness( double[] data, int windowSize, int predictionSize, double[] constants )
		{
			// check for correct parameters
			if ( windowSize >= data.Length )
				throw new ArgumentException( "Window size should be less then data amount" );
			if ( data.Length - windowSize - predictionSize < 1 )
				throw new ArgumentException( "Data size should be enough for window and prediction" );
			// save parameters
			this.data			= data;
			this.windowSize		= windowSize;
			this.predictionSize	= predictionSize;
			// copy constants
			variables = new double[constants.Length + windowSize];
			Array.Copy( constants, 0, variables, windowSize, constants.Length );
		}

		/// <summary>
		/// Evaluates chromosome
		/// </summary>
		/// 
		/// <param name="chromosome">Chromosome to evaluate</param>
		/// 
		/// <returns>Returns chromosome's fitness value</returns>
		///
		/// <remarks>The method calculates fitness value of the specified
		/// chromosome.</remarks>
		///
		public double Evaluate( IChromosome chromosome )
		{
			// get function in polish notation
			string function = chromosome.ToString( );

			// go through all the data
			double error = 0.0;
			for ( int i = 0, n = data.Length - windowSize - predictionSize; i < n; i++ )
			{
				// put values from current window as variables
				for ( int j = 0, b = i + windowSize - 1; j < windowSize; j++ )
				{
					variables[j] = data[b - j];
				}

				// avoid evaluation errors
				try
				{
					// evaluate the function
					double y = PolishExpression.Evaluate( function, variables );
					// check for correct numeric value
					if ( double.IsNaN( y ) )
						return 0;
					// get the difference between evaluated value and
					// next value after the window, and sum error
					error += Math.Abs( y - data[i + windowSize] );
				}
				catch
				{
					return 0;
				}
			}

			// return optimization function value
			return 100.0 / ( error + 1 );
		}

		/// <summary>
		/// Translates genotype to phenotype 
		/// </summary>
		/// 
		/// <param name="chromosome">Chromosome, which genoteype should be
		/// translated to phenotype</param>
		///
		/// <returns>Returns chromosome's fenotype - the actual solution
		/// encoded by the chromosome</returns> 
		/// 
		/// <remarks>The method returns object, which represents prediction
		/// expression written in polish postfix notation. The object's type is
		/// string. See <see cref="TranslateNative"/> for more details.</remarks>
		///
		public object Translate( IChromosome chromosome )
		{
			return TranslateNative( chromosome );
		}

		/// <summary>
		/// Translates genotype to phenotype 
		/// </summary>
		/// 
		/// <param name="chromosome">Chromosome, which genoteype should be
		/// translated to phenotype</param>
		///
		/// <returns>Returns chromosome's fenotype - the actual solution
		/// encoded by the chromosome</returns> 
		/// 
		/// <remarks>The method returns string value, which represents prediction
		/// expression written in polish postfix notation.<br /><br />
		/// The interpretation  of the prediction expression is very simple. For example, let's
		/// take a look at sample expression, which was received with window size equal to 5:
		/// <code>$0 $1 - $5 / $2 *</code>
		/// The above expression in postfix polish notation should be interpreted as a next expression:
		/// <code>( ( x[t - 1] - x[t - 2] ) / const1 ) * x[t - 3]</code>
		/// </remarks>
		///
		public string TranslateNative( IChromosome chromosome )
		{
			// return polish notation for now ...
			return chromosome.ToString( );
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer IBM
United Kingdom United Kingdom
Started software development at about 15 years old and it seems like now it lasts most part of my life. Fortunately did not spend too much time with Z80 and BK0010 and switched to 8086 and further. Similar with programming languages – luckily managed to get away from BASIC and Pascal to things like Assembler, C, C++ and then C#. Apart from daily programming for food, do it also for hobby, where mostly enjoy areas like Computer Vision, Robotics and AI. This led to some open source stuff like AForge.NET, Computer Vision Sandbox, cam2web, ANNT, etc.

Comments and Discussions