Swiftvolution – Candidate Factories

More on the Generational Evolution Engine

The generational evolution engine is a simple evolution engine that evolves things in generations. The basic algorithm is as follows:

  • Create initial population
  • Evaluate initial population
  • while termination condition not met
    • select parents of next generation
    • evolve children from parents
    • evaluate children

The basics of the generational evolution engine are defined as follows:

public struct GenerationalEvolutionEngine<CF: CandidateFactory>: EvolutionEngine
{
    public typealias EvolveType = CF.ProduceType

    // Some stuff

    public init(candidateFactory: CF,
               evolutionOperator: @escaping EvolutionOperator<EvolveType>,
                fitnessEvaluator: @escaping (EvolveType, [EvolveType]) -> Double,
                       isNatural: Bool = true,
               selectionStrategy: @escaping ([EvaluatedCandidate<EvolveType>], Bool, Int, PRNG) -> [EvolveType],
                			 rng: PRNG)
    {
        // Some stuff
    }

    // implementation
}

 

The rest of this post is based on the Candidate Factory section of the Watchmaker user manual.

Here is the CandidateFactory protocol

public protocol CandidateFactory
{
    /// The type of thing to produce
    associatedtype ProduceType

    /// Generate a single random candidate
    ///
    /// - Parameter rng: The random number generator to use.
    /// - Returns: A random candidate
    func generateRandomCandidate(rng: PRNG) -> ProduceType
}

I could have just made it a function, but in most cases you don’t want one candidate but a whole population of candidates, and there is often context required that affects how the candidates are generated. Therefore, it seemed cleaner to make it a protocol with an extension for generating a population.

public extension CandidateFactory
{
    /// Create a random population possibly using a seed population. If there are
    /// more seeds than we need for the whole population, use the first `count` of them.
    ///
    /// - Parameters:
    ///   - count: Number of individuals in the population.
    ///   - seeds: Preselected seed individuals
    ///   - rng: Random number generator
    /// - Returns: An array of `ProduceType` to act as the population.
    public func generateInitialPopulation(count: Int, seeds: [ProduceType] = [], rng: PRNG) -> [ProduceType]
    {
        guard seeds.count < count
        else
        {
            return Array(seeds[0 ..< count])
        }
        var ret: [ProduceType] = seeds
        while ret.count < count
        {
            ret.append(generateRandomCandidate(rng: rng))
        }
        return ret
    }
}

Note that the candidate factory produces an array of ProduceType and that the generational evolution engine aliases it to its EvolveType. This means that the Swift compiler can infer pretty much everything about the evolution engine’s type from the first parameter of its initialiser.

That’s all there is to it as far as the candidate factory is concerned. Next we will talk about evolution operators.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.