GeneticAlgorithms 0.0.1
See the version list below for details.
dotnet add package GeneticAlgorithms --version 0.0.1
NuGet\Install-Package GeneticAlgorithms -Version 0.0.1
<PackageReference Include="GeneticAlgorithms" Version="0.0.1" />
<PackageVersion Include="GeneticAlgorithms" Version="0.0.1" />
<PackageReference Include="GeneticAlgorithms" />
paket add GeneticAlgorithms --version 0.0.1
#r "nuget: GeneticAlgorithms, 0.0.1"
#:package GeneticAlgorithms@0.0.1
#addin nuget:?package=GeneticAlgorithms&version=0.0.1
#tool nuget:?package=GeneticAlgorithms&version=0.0.1
Genetic Algorithms
GeneticAlgorithms is a small F# library for experimenting with genetic algorithms. It provides a compact, generic execution pipeline for evolving chromosomes and includes example projects that demonstrate both binary and character-based optimization problems.
The repository is structured as an educational, easy-to-read implementation rather than a feature-complete optimization framework. The core abstractions are intentionally small so you can understand how the algorithm works and adapt it for your own problems.
Inspiration
This library is heavily influenced by the ideas and teaching approach in Genetic Algorithms in Elixir: Solve Problems Using Evolution by Sean Moriarity. If you want a practical introduction to evolutionary algorithms and how to structure them in code, it is a strong companion resource for this repository.
Features
- Generic chromosome representation with support for any gene type
- Problem definition through pluggable genotype, fitness, and termination functions
- Population evaluation with age tracking and fitness sorting
- Parent pairing for even and odd population sizes
- Single-point crossover
- Mutation by random gene shuffling
- Included examples and automated tests
Project Structure
src/GeneticAlgorithms Core library
examples/HelloWorld/csharp C# character-based string evolution example
examples/HelloWorld/fsharp F# character-based string evolution example
examples/Knapsack/csharp C# constrained optimization example
examples/OneMaxProblem/csharp C# binary optimization benchmark example
examples/OneMaxProblem/fsharp F# binary optimization benchmark example
examples/Knapsack/fsharp F# constrained optimization example
tests/GeneticAlgorithms.Tests Automated tests with Expecto
tests/GeneticAlgorithms.CSharpSmoke Minimal C# consumer validating the interop layer
Core Concepts
The library revolves around three types:
Chromosome<'T>
Represents a candidate solution.
type Chromosome<'T> =
{ genes: 'T array
size: int
fitness: float
age: int }
Problem<'Gene>
Defines how a specific optimization problem behaves.
type Problem<'Gene> =
{ genotype: unit -> Chromosome<'Gene>
fitness_function: Chromosome<'Gene> -> float
terminate: seq<Chromosome<'Gene>> -> int -> float -> bool }
Options
Controls runtime configuration.
type Options = { population_size: int }
Algorithm Flow
Genetic.run executes the following loop:
- Initialize a population using the supplied genotype function.
- Evaluate all chromosomes with the fitness function.
- Sort the population by descending fitness.
- Select parents by pairing neighboring chromosomes.
- Produce children using single-point crossover.
- Apply mutation to some chromosomes.
- Repeat until the termination function returns
truefor the current population, generation, and temperature.
During execution, the current best fitness is printed for each generation. The termination callback receives the evaluated population, the current generation number, and a temperature value computed from recent fitness progress, so problems can stop either on solution quality, a generation cap, temperature behavior, or a combination of those signals.
Getting Started
Requirements
- .NET 9 SDK
Build the solution
From the repository root:
dotnet build genetic-algorithms.sln
Run the tests
dotnet run --project tests/GeneticAlgorithms.Tests/GeneticAlgorithms.Tests.fsproj
Basic Usage
Define a genotype function, a fitness function, and a termination condition, then call Genetic.run.
open GeneticAlgorithms
let genotype () =
let genes = Array.init 10 (fun _ -> System.Random.Shared.Next(0, 2))
{ genes = genes
size = genes.Length
fitness = 0.0
age = 0 }
let fitness_function (chromosome: Chromosome<int>) =
chromosome.genes |> Array.sum |> float
let terminate (population: seq<Chromosome<int>>) (_generation: int) (_temperature: float) =
population |> Seq.exists (fun chromosome -> chromosome.fitness >= 10.0)
let problem: Problem<int> =
{ genotype = genotype
fitness_function = fitness_function
terminate = terminate }
let options = { population_size = 100 }
let solution = Genetic.run problem options
C# Interop
The core API is implemented in idiomatic F#, but the library also exposes a small C#-friendly facade through GeneticAlgorithms.GeneticAlgorithm. This avoids forcing C# examples to construct F# records with curried function fields directly.
using GeneticAlgorithms;
var solution = GeneticAlgorithm.Run(
genotype: () => GeneticAlgorithm.CreateChromosome(new[] { Random.Shared.Next(0, 2) }),
fitnessFunction: chromosome => chromosome.Genes[0],
terminate: (population, generation, temperature) =>
population.Any(chromosome => chromosome.Fitness >= 1.0) || generation >= 10,
populationSize: 8);
The older Interop type remains available as a compatibility wrapper, but new C# examples should prefer GeneticAlgorithm.
The smoke project in tests/GeneticAlgorithms.CSharpSmoke exists specifically to validate that this API stays straightforward to consume from C#.
Examples
See examples/README.md for an index of all example projects and their available language variants.
HelloWorld
The HelloWorld example evolves a random lowercase character string toward the target helloworld. Its fitness function uses Jaro similarity, which makes it a simple example of working with char chromosomes instead of binary genes.
Its termination function checks the current population and ignores the generation and temperature arguments because the fitness threshold alone is enough for this example.
Run it with:
dotnet run --project examples/HelloWorld/fsharp
There is also a C# version of the same example:
dotnet run --project examples/HelloWorld/csharp
Typical output ends with a string result similar to:
Best solution: helloworld (fitness: 1.000000)
OneMaxProblem
The OneMax example solves the classic benchmark problem of maximizing the number of 1s in a binary chromosome.
Like HelloWorld, it stops based on population fitness and ignores the generation and temperature arguments passed to the termination callback.
Run it with:
dotnet run --project examples/OneMaxProblem/fsharp
There is also a C# version of the same example:
dotnet run --project examples/OneMaxProblem/csharp
Knapsack
The Knapsack example solves a small 0/1 knapsack problem where binary genes indicate whether an item is packed. Candidate solutions that exceed the weight limit receive zero fitness.
Run it with:
dotnet run --project examples/Knapsack/fsharp
There is also a C# version of the same example:
dotnet run --project examples/Knapsack/csharp
This example is useful for exploring constrained optimization rather than pure maximization.
This is a useful baseline for validating the library's evaluation, selection, crossover, and mutation behavior.
Test Coverage
The test project currently verifies the main building blocks of the algorithm:
Genetic.evaluateapplies fitness, increments age, and sorts by descending fitnessGenetic.selectpairs chromosomes correctly for even and odd populationsGenetic.crossoverpreserves chromosome size and recombines parent genesGenetic.mutationpreserves population size and gene membershipGenetic.initializecreates the requested number of chromosomesGenetic.runreturns the fittest chromosome when termination is reachedGenetic.runforwards generation and temperature values to the termination callback
Design Notes
This implementation is intentionally minimal. A few design choices to be aware of:
- Mutation currently shuffles the genes within a chromosome rather than replacing individual genes with newly generated values
- Selection pairs adjacent chromosomes after sorting rather than using tournament or roulette-wheel selection
- The runtime options currently expose only population size
Those constraints keep the code simple, but they also make the project a good starting point for extending the algorithm with stronger selection strategies, richer mutation operators, elitism, configurable stopping criteria, or additional runtime parameters.
Repository Goals
This project is a good fit if you want to:
- Learn how a genetic algorithm can be implemented in F#
- Experiment with generic chromosome representations
- Build on a small codebase instead of adopting a large framework
- Add new example problems and compare evolutionary behavior
License
This repository is licensed under the terms of the LICENSE file in the project root.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- FSharp.Core (>= 10.1.302)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.