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;
}
}
}