A genetic algorithm library for Swift.
- Rank
- Roulette
- Tournament
- Stochastic
- Custom
- N-Point
- Uniform
- Custom
Add the following to the dependencies
in your Package.swift
file.
dependencies: [
.package(url: "https://github.com/colinc86/Genetics.git, from: "1.0.0")
]
- Navigate to your project's directory and clone the Genetics repository.
$ git clone https://github.com/colinc86/Genetics.git
- Add
Genetics.xcodeproj
to your Xcode project. - Add the
Genetics
framework to your project.
For a working example, see the GeneticsExample.
A few things need to be set up before evolution can take place. We must have a population of chromosomes to evolve, and a set of parameters to guide the evolution of each generation. The Chromosome
, Population
and EvolverConfiguration
objects are what we'll use.
The first thing you'll need to do is generate a population of chromosomes. The easiest way to do that is by using the static function Population.generate(populationSize:chromosomeLength:generatingFunction:)
. The following example generates a Population
of 4 chromosomes with length 2 by using the provided generating function.
var population = Population.generate(populationSize: 4, chromosomeLength: 2) { (_, _) -> Double in
return arc4random_uniform(20)
}
You can also create chromosomes manually by initializing them with an array or an array literal.
let chromosomeA = Chromosome([1.0, 2.0, 3.0])
let chromosomeB = Chromosome(1.0, 2.0, 3.0)
Then, initialize a Population
with an array of chromosomes.
let population = Population([chromosomeA, chromosomeB])
An instance of EvolverConfiguration
contains parameters for use by an Evolver
when performing evolution. Creating one is easy:
let configuration = EvolverConfiguration(selectionMethod: .rank, crossoverMethod: .point(count: 1), elitism: .none, crossoverRate: 0.1, mutationRate: 0.1)
The class responsible for evolving a population of chromosomes is the Evolver
. You create an evolver by giving it a configuration, fitness function, and a mutation function. The fitness function is responsible for returning the fitness of a chromosome in the population, and the mutation function is responsible for mutating a single element of a chromosome.
The following example creates an instance of Evolver
with configuration
and provides fitness and mutation functions. The fitness function divides 10.0 by the sum of all of the elements in the chromosome. The mutation function randomly adds or subtracts 1 from an element of the chromosome and returns the result. This will result in the fittest chromosomes having elements whos sum is near 10.0.
let evolver = Evolver(configuration: configuration, fitnessFunction: { (chromosome: Chromosome) -> Double in
// Fitness function
return 10.0 / chromosome.reduce(0, +)
}, mutationFunction: { (chromosome: Chromosome, index: Int) -> Double in
// Mutation function
var value = chromosome[index]
value += arc4random_uniform(2) == 0 ? -1.0 : 1.0
return value
})
The easiest way to evolve a population is by using the evolver's evolve(population:shouldContinue:)
function.
do {
try evolver.evolve(population: &population, shouldContinue: { (config: inout EvolverConfiguration, pop: Population) -> Bool in
return pop.generation < 100
})
}
catch let error {
print("\(error)")
}
The preceding example evolves the population 100 times. Notice that the shouldContinue
closure takes an inout EvolverConfiguration
parameter. The evolver gives you the chance to modify its configuration before the next evolution cycle.
You can also call evolve
once without providing the shouldContinue
closure.
do {
for _ in 0 ..< 100 {
try evolver.evolve(population: &population)
}
}
catch let error {
print("\(error)")
}
Genetics is released under the MIT license.
See LICENSE.