MAPElites.jl

MAPElites.jl APIs

MAPElites.jl maximizes modularity and extensibility by using a strategy design pattern. A full MAPElites container takes a variation strategy for mutating candidate solutions, a fitness strategy for evaluating candidate fitness, and a behavior descriptor strategy for calculating behavior descriptors for candidate solutions. Each solution, along with its behavior descriptor, and fitness are stored in an archive, which is a subtype of an AbstractArchive. These components are explained more below.

AbstractArchive

The MAPElites struct expects an archive that implements the AbstractArchive API to store solutions. All subtypes of AbstractArchive must implement the findniche and Base.setindex! functions. The findniche method must take as inputs a concrete archive and a behavior descriptor vector and return an index in the archive that corresponds to the given behavior descriptor. The setindex! method must set or update the given index in the archive with the given solution, behavior descriptor, and fitness. Optionally, a subtype of AbstractArchive may also include selectrandom, selectbestelite, and selectworstelite methods that return a tuple containing a solution, behavior descriptor, and fitness that is either random, the best solution, or the worst solution. In any case, all concrete archives must have at least one method to retrieve an elite, and selectrandom, selectbestelite, and selectworstelite are suggested methods.

VariationStrategy

Running MAP-Elites or a variant requires some way to create child solutions by mutating or changing parent solutions. In MAPElites.jl, this is a variation strategy that is a subtype of the VariationStrategy abstract type. A concrete variation strategy can contain arbitrary fields, e.g. to keep track of the iteration or parameters for a normal distribution. Additionally, a concrete variation strategy must have an associated functor that accepts a candidate solution and returns a new candidate solution.

FitnessStrategy

Running MAP-Elites also requires some way to evaluate the fitness of candidate solutions, which is accomplished by using a fitness strategy. Fitness strategies must be subtypes of the FitnessStrategy abstract type. Concrete fitness strategies may have any arbitraryi fields. For example, a fitness strategy may include a surrogate model such as a Gaussian process regression to avoid computing an expensive fitness function at every iteration. Like variation strategies, fitness strategies must implement a functor that accepts a candidate solution as an argument and returns a concrete subbtype of Real.

BehaviorDescriptorStrategy

A key ingredient of MAP-Elites and its variants is a behavior descriptor. In MAPElites.jl, this takes the form of behavior descriptor strategies. All concrete behavior descriptor strategies must be subtypes of the BehaviorDescriptorStrategy abstract type and implement a functor that takes in a raw behavior descriptor and outputs a behavior descriptor vector. Like other strategies, subtypes can store arbitrary information and can be as simple as returning the behavior descriptor that is passed as an argument or as complicated as using a dimensionality reduction technique like a VAE.

Modules

MAPElitesModule

MAPElites contains implementations of the MAP-Elites, CVT-MAP-Elites, AURORA, SAIL, and CMA-MAP-Elites as well as archives, fitness strategies and functors, behavior descriptor strategies and functors, variation operators, and selection operators that can be mixed and matched.

For more information on MAP-Elites, see: Mouret, Jean-Baptiste, and Jeff Clune. "Illuminating search spaces by mapping elites." arXiv preprint arXiv:1504.04909 (2015).

source

Abstract Types

MAPElites.AbstractArchiveType

An abstract type that all archives must be subtypes of. All subtypes must implement the findniche, Base.setindex!, selectrandom, selectbestelite, and selectworstelite methods.

source
MAPElites.VariationStrategyType

An abstract type that all variation strategies must be subtypes of. Concrete variation strategies can store any state information such as iterations or hyperparameters and must implement the vary method.

source
MAPElites.FitnessStrategyType

An abstract type that all fitness strategies must be subtypes of. Concrete fitness strategies can store state information such as iterations, hyperparemeters, or other data structures. For example, a fitness strategy could store a surrogate model to avoid evaluating a costly fitness function at every iteration. All subtypes must implement a fitness method.

source
MAPElites.BehaviorDescriptorStrategyType

An abstract type that all concrete behavior descriptor strategies must be subtypes of. In its simplest form, a behavior descriptor strategy can just return the original behavior descriptor vector it is passed. However, a behavioral descriptor strategy could also store state information or dimensionality reduction methods, for example. All subtypes must implement a describe_behavior method.

source

Structs

MAPElites.AlgorithmType
Algorithm(arch, sel, var_strat, fit_strat, bd_strat, init, [, k, iterations])

Initialize an algorithm type to run MAP-Elites or one of its variants.

Arguments

  • arch::AbstractArchive: A subtype of AbstractArchive for storing solutions.
  • sel::Function: A function to select a solution grom the archive.
  • var_strat::VariationStrategy: A subtype of VariationStrategy to vary or mutate solutions.
  • fit_strat::FitnessStrategy: A subtype of FitnessStrategy to evaluate solutions.
  • bd_strat::BehaviorDescriptorStrategy: A subtype of BehaviorDescriptorStrategy to generate behavior descriptors.
  • init::Function: A function that accepts a random number generator and returns a solution for initializing the archive.
  • k::Int=1000: The number of candidates to generate for initialization.
  • iterations::Int=10000: The number of iterations to run the algorithm for.

Examples

julia> dims, lb, ub = (3, 4), (0.0, -1.0), (1.0, 2.0)
julia> g = GridArchive(dims, lb, ub)
julia> sel = select_random()
julia> var_strat = CMA()
julia> init = my_initializer()
julia alg = Algorithm(g, sel, var_strat, init)
source

Functions

MAPElites.find_nicheFunction

Find the index of the archive for the corresponding behavior descriptor.

This method must be implemented for all subtypes of AbstractArchive. When implementing a new find_niche method on a subtype of AbstractArchive, the method must return a tuple corresponding to the index in the archive.

source
Base.getindexFunction
Base.getindex(g, key...)

Get a tuple of the solution, behavior_descriptor, and fitness of the corresponding index.

Arguments

  • g::GridArchive: A GridArchive to retrive the data from.
  • key...::Tuple: A tuple corresponding to the index to retrieve data from.

Examples

julia> dims, lb, ub = (5,), (0.0,), (10.0,)
julia> g = GridArchive(dims, lb, ub)
julia> idx = 2, 1
julia> g[idx...]
(nothing, nothing, nothing)
source
Base.setindex!Function
Base.setindex!(g, value, key...)

Set the solution, behavior_descriptor, and fitness of the corresponding index in a GridArchive.

Arguments

  • g::GridArchive: A GridArchive to retrive the data from.
  • value::Tuple{Any, AbstractVector{<:Real}, <Real}: The solution, behavior descriptor, and fitness function to assign to the key.
  • key...::Tuple: A tuple corresponding to the index to retrieve data from.

Examples

julia> dims, lb, ub = (5,), (0.0,), (10.0,)
julia> g = GridArchive(dims, lb, ub)
julia> idx = 2, 1
julia> g[idx...] = (90, [1.0, 2.0], 3.0)
julia> g[idx...]
(90, [1.0, 2.0], 3.0)
source
MAPElites.select_randomFunction

Get a random solution and its corresponding behavior descriptor and fitness from an archive.

This method may optionally be extened to new subtypes of AbstractArchive. When implementing a new select_random method on a subtype of AbstractArchive, the method must return a tuple of solution, behavior descriptor, fitness.

source
MAPElites.select_best_eliteFunction

Get the best performing solution and its corresponding behavior descriptor and fitness from an archive.

This method may optionally be extended to new subtypes of AbstractArchive. When implementing a new selectbestelite method on a subtype of AbstractArchive, the method must return a tuple of soltuion, behavior descriptor, fitness.

source
MAPElites.select_worst_eliteFunction

Get the worst performing solution and its corresponding behavior descriptor and fitness from an archive.

This method may optionally be extended to subtypes of AbstractArchive. When implementing a new selectworstelite method on a subtype of AbstractArchive, the method must return a tuple of soltuion, behavior descriptor, fitness.

source

Contributing

All contributions are welcome. To ensure contributions align with the existing code base and are not duplicated, please follow the guidelines below.

Reporting a Bug

To report a bug, open an issue on GitHub page. Please include all relevant information, such as what methods were called, the operating system used, the verion/s of MAPElites.jl used, the verion/s of Julia used, any tracebacks or error codes, and any other information that would be helpful for debugging. Also be sure to use the bug label.

Requesting New Features

Before requesting a new feature, please check the issues page on GitHub to make sure someone else did not already request the same feature. If this is not the case, then please open an issue that explains what function or method you would like to be added and how you believe it should behave. Also be sure to use the enhancement tag.

Contributing Code

Before submitting a pull request, please open an issue explaining what the proposed code is and why you want to add it, if there is not already an issue that addresses your changes and you are not fixing something very minor. When submitting a pull request, please reference the relevant issue/s and ensure your code follows the guidelines below. Please also see above for an overview of how this package and its components are designed.

  • Before being merged, all pull requests should be well tested and all tests must be passing.

  • All abstract types, structs, functions, methods, macros, and constants have docstrings that follow the same format as the other docstrings. These functions should also be included in the relevant section above.

  • There are no repeated code blocks. If there are repeated codeblocks, then they should be consolidated into a separate function.

  • Internal methods can contain types and be parametric but public methods should be as general as possible.

  • Minimize use of new constants and macros. If they must be included, the reason for their inclusion should be obvious or included in the docstring.

  • In most cases, avoid using global variables and constants.

  • Code should take advantage of Julia's built in macros for performance. Use @inbounds, @view, @fastmath, and @simd when possible.

  • When appending to an array in a loop, preallocate the array and update its values by index.

  • Avoid long functions and decompose them into smaller functions or methods. A general rule is that function definitions should fit on your screen.

  • Use self-explanatory names for variables, methods, structs, constants, and macros.

  • Make generous use of whitespace.

  • All functions should include docstrings.

Note

MAPElites.jl follows the Blue style guide and all code is automatically formatted to conform with this standard upon being pushed to GitHub.

Updating or Fixing Documentation

To propose a change to the documentation please submit an issue or pull request.