Getting Started with the F# Artificial Intelligence library

This step-by-step tutorial describes how to use the library in fsx script and C# project.

1. Solving dependencies

The library uses RandomOps library for generating random numbers. Source-code of RandomOps library is published under the GNU Lesser General Public License and can be found here.
As the first step it is necessary to download source-code of RandomOps and compile it to the dll file. How-to-do instructions are part of zip archive containing source-code.

2. Creating RandomOps wrapper for F#

  • Create new C# Class Library project in Microsoft Visual Studio
  • Add reference to compiled RandomOps.dll file
  • Create Global Object of RandomOps in accordance with manual of RandomOps library. Manual is available here.
namespace Rnd
{
    public static partial class Globals
    {
        public static RandomOps.Ran2 Random = new RandomOps.Ran2();
    }
  • Because F# cannot operate with partial classes it is necessary to write following class.
namespace Rnd
{
    public static partial class Globals
    {
        public static RandomOps.Ran2 Random = new RandomOps.Ran2();
    }

    public static class RandomNumber
    {
        public static double GetRandom(double min, double max)
        {
            return Globals.Random.Uniform(min, max);
        }
    }
}
  • Now the wrapper library can be compiled.

3.1 Using F# Artificial Intelligence library in fsx script

  • Create folder e.g. C:\fsai and place following files there
    • RandomOps.dll - compiled RandomOps library
    • Rnd.dll - compiled RandomOps wrapper
    • FSharp.AI.dll - AI library
    • TestFunctions.fs - optional
  • Create new fsx script file
// Path where libraries are placed
#I @"C:\fsai"

// Reference to main library
#r "FSharp.AI.dll"

// Loading of F# module
#load "TestFunctions.fs"

// Opening of namespace and module
open FSharp.AI
open TestFunctions

//
//  Initialization of Differential Evolution
//
// Mutation constant
let f = 0.9
// Cross-over value
let cr = 0.2
// Number of population
let np = 60
// Number of generations
let generations = 60
// Type of Differential Evolution
let typ = DEVariant.DERand1Bin

//
//  Definition of Specimen
//  ------------------------
//  Each argument has specified type (int or float) and minimum - maximum values.
//  In this case the specimen has two arguments. Both arguments have defined range <-5; 5> of float type.
//
let Specimen = [
    new SpecimenArgument (typeof<float>, -5., 5.)
    new SpecimenArgument (typeof<float>, -5., 5.) ]

//
//  Definition of Cost Function
//  -----------------------------
//  This function provides evaluation of individuals.
//  The structure of this function cannot be changed, but computation of cost value.
//
let CostFunction (individual : float[]) : float[] = 
    // Cost value
    let mutable cv = 0.
    //---------------------------------
    // This part should contain computation of cost value and can be changed.

    // Example of using test function
    // individual.[1] - accessing first argument of individual - defined in accordance to first argument of specimen
    // individual.[2] - accessing second argument of individual - defined in accordance to second argument of specimen
    cv <- DeJong1st [individual.[1]; individual.[2]]
    //----------------------------------
    individual.[0] <- cv
    individual

// Creating Object
let evolution = new DE()
// Running evolution
let (result, progress) = evolution.RunEvolution (f, cr, np, generations, Specimen, typ, CostFunction)

// Result variable contains individuals of the last generation. Following code selects an individual with minimal cost value.
// First printed number is the cost value, others are arguments of individuals
printfn "%A" (Array.min result)

// Cost values of best individuals over all generations
printfn "%A" progress

System.Console.ReadKey()

Notes

In the example script is used DeJong1st test function for calculating the cost value. This function is a part of TestFunctions.fs which can be downloaded here. TestFunction.fs file contains several commonly-used functions for proving capabilities of evolutionary algorithms. Description of these functions can be found e.g. here.

3.2 Using F# Artificial Intelligence library in C# project

  • In Visual Studio, create new C# ConsoleApplication which is based on .NET Framework 4.
  • Add references to FSharp.AI.dll and FSharp.Core.dll version 4.

using System;
using System.Collections.Generic;
using System.Text;
using FSharp.AI;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            //
            // Initialization of Differential Evolution
            //
            // Mutation constant
            double f = 0.9;
            // Cross-over value
            double cr = 0.2;
            // Number of population
            int np = 60;
            // Number of generations
            int generations = 60;
            // Type of Differential Evolution
            DEVariant typ = DEVariant.DERand1Bin;

            //
            // Definition of Specimen
            // -----------------------
            // Each argument has specified type (int or double) and minimum - maximum values.
            // In this case the specimen has two arguments. Both arguments have defined range <-5; 5> of double type.
            //
            List<SpecimenArgument> Specimen = new List<SpecimenArgument>()
            {
                new SpecimenArgument(typeof(double), -5, 5),
                new SpecimenArgument(typeof(double), -5, 5)
            };

            // Delegate of Cost Function method
            Func<double[], double[]> CostFunction = CF;
            
            // Creating DE object
            DE evoluce = new DE();

            // Running evolution
            Tuple<double[][], double[]> vysledek = evoluce.RunEvolution(f, cr, np, generations, Specimen, typ, CostFunction);

            // Finding best individual (C# doesn't contain Array.min)
            double[] nejlepsi = FindBestOne(vysledek.Item1);

            // Printing results
            StringBuilder sb = new StringBuilder();
            sb.Append("CV: ");
            sb.Append(nejlepsi[0].ToString());
            sb.Append("; argumenty: ");
            for (int i = 1; i < nejlepsi.Length; i++)
            {
                sb.Append(nejlepsi[i].ToString());
                sb.Append(";");
            }
            Console.WriteLine(sb.ToString());
            Console.ReadKey();            
        }

        // Cost Function
        static double[] CF(double[] individual)
        {
            double cv = 0;

            // Implementation of 1st de Jong function
            for (int i = 1; i < individual.Length; i++)
            {
                cv += (individual[i] * individual[i]);
            }

            individual[0] = cv;

            return individual;
        }

        // This method finds best individual
        static double[] FindBestOne(double[][] generace)
        {
            double[] bestOne = generace[0];

            for (int i = 1; i < generace.Length; i++)
            {
                if (generace[i][0] < bestOne[0])
                {
                    bestOne = generace[i];
                }
            }

            return bestOne;
        }

    }
}

Last edited Aug 27, 2010 at 6:08 PM by lko, version 11

Comments

No comments yet.