Jevo._WeightCache
— Type_WeightCache::LRU{Int, <:Array{Float32}}
Stores developed tensors of weights for genes. Keys are tensor dimensions and the last gene id used. For a weight of dimensions (a, b)
containing gene ids 1, 2, 3
, _WeightCache[3, (a,b)]
would map to a tensor equivalent to tensor(gene_1) + tensor(gene_2) + tensor(gene_3)
.
Jevo.AllVsAllMatchMaker
— TypeAllVsAllMatchMaker(ids::Vector{String}=String[];kwargs...)
Creates an Operator that creates all vs all matches between individuals in populations with ids in ids
.
Jevo.Assertor
— MethodAssertor(;kwargs...)
Creates an Operator that asserts some condition. You probably want to override the retriever
operator
fields.
Jevo.ClearInteractionsAndRecords
— TypeClearInteractionsAndRecords(;kwargs...)
Clears all interactions and records from all individuals in the state.
Jevo.CloneUniformReproducer
— TypeCloneUniformReproducer(pop_size::Int, ids::Vector{String}=String[]; kwargs...)
Creates an Operator that choose individuals uniformly at random and clones them, creating children with identical DNA, until the population reaches pop_size
individuals.
Should be used after a selector.
See also: TruncationSelector
Jevo.CompositePopulation
— TypeCompositePopulation(id::String, populations::Vector{<:AbstractPopulation})
A population composed of subpopulations. Can be used to hierarchically organize populations.
Jevo.CompositeWeight
— Typestruct CompositeWeight{T<:AbstractWeights} <: AbstractWeights
dims::Tuple{Vararg{Int}}
weights::Vector{T}
end
A collection of weights which are added together. Each element must develop to the same size
Jevo.ComputeInteractions!
— TypeJevo.Counter
— TypeCounter(type::Type)
Holds an integer to increase by 1 with inc!(counter::Counter)
. Used for tracking gene ids, generations, individual ids, etc. Counters have a default value of 1
.
Jevo.CreateMissingWorkers
— TypeCreates up to n
workers
Jevo.Creator
— Typestruct Creator{T} <: AbstractCreator where T
type::Type{T}
kwargs::Union{NamedTuple,Tuple}
end
A creator is a struct that contains a type to create and the arguments to pass to the constructor. If arguments contain other creators, those are recursively created first, unless enclosed in a PassThrough. We use a creator to allow for creating multiple objects which may include random initialization with a single creator.
See also: PassThrough, create
Jevo.Delta
— TypeDelta{G} <: AbstractGenotype where {G <: AbstractGenotype}
A delta is a change in a genotype. It can be applied to a genotype to create a new genotype, with the differences applied.
Jevo.FactorWeight
— Typestruct FactorWeight{F1<:AbstractWeights, F2<:AbstractWeights} <: AbstractWeights
dims::Tuple{Vararg{Int}}
A::F1
B::F2
end
Low-rank factorization of a weight matrix
Jevo.GenePool
— TypeGenePool(deltas::Vector)
A gene pool is a collection of deltas.
Jevo.GenerationIncrementer
— MethodGenerationIncrementer(;kwargs...)
Increments the generation counter in the state by 1.
Jevo.Individual
— Typemutable struct Individual{G,D,I} <: AbstractIndividual where
{G <: AbstractGenotype,
D <: AbstractCreator,
I <: AbstractInteraction}
id::Int
generation::Int
parents::Vector{Int}
genotype::G
developer::D
records::Vector{AbstractRecord}
interactions::Vector{I}
data::Vector
end
An individual is a single entity in the population. Each individual should have a unique id generated from an AbstractIndividual
Counter. An individual's developer
is a creator that turns a genotype into a phenotype.
Jevo.Individual
— MethodIndividual(counters::Vector{<:AbstractCounter},
genotype_creator::Creator,
developer::AbstractCreator)
Create new individual with no parents
Jevo.InitializeAllPopulations
— TypeSamples 1 population from each population creator and puts them into state.populations
Jevo.InitializeDeltaCache
— TypeInitializeDeltaCache(ids::Vector{String}=String[];kwargs...)
Creates a cache of Deltas for a population.
Jevo.InitializePhylogeny
— TypeInitializePhylogeny(ids::Vector{String}=String[];kwargs...)
Initializes a phylogenetic tree for populations with ids in ids
. The tree is initialized with the current generation's individuals as the genesis individuals. The tree is initialized only once, and will throw an error if called multiple times on the same population.
See also LogPhylogeny, UpdatePhylogeny, PurgePhylogeny
Jevo.LogPhylogeny
— TypeLogPhylogeny(ids::Vector{String}=String[]; kwargs...)
Adds recent individuals to a phylogeny file called $(pop.id)-phylo.csv
in the current directory. The file is formatted as a CSV with columns id
and ancestor_list
, according to the ALIFE Data Standard
Jevo.Match
— Typestruct Match{I,E} <: AbstractMatch where {I <: AbstractIndividual, E <: AbstractEnvironment}
id::Int
individuals::Vector{I}
environment_creator::Creator{E}
end
Jevo.MaxMRs
— TypeConsists of a genotype with at most one gene per weight. Each gene has the largest MR in the genepool for that weight. The ids, seeds, and inits are irrelevant for these.
Jevo.Mutator
— TypeMutator(ids::Vector{String}=String[]; time::Bool=false, condition=always, kwargs...)
Operator that mutates the genotypes of individuals in populations with ids in ids
. Calls mutate! on each individual in each population.
Jevo.Network
— TypeA collection of sequential layers
Jevo.NetworkGene
— Typestruct NetworkGene <: AbstractMutation
id::Int
seed::UInt64
mr::Float32
init!::Union{AbstractInitializer,Function}
end
Gene for a Weights object, used to generate a tensor of Float32
. A StableRNG
object is created with seed seed
, which is then passed into init!
to generate the tensor. The tensor is then mutated by mutation rate mr
. id
is a unique identifier for the gene.
Jevo.Operator
— TypeOperator <: AbstractOperator
All operator structs should be defined with the @define_op
macro, and all operators should be created with the create_op
function. Each operator should have the following fields:
condition::Function
retriever::Union{Function, AbstractRetriever}
operator::Function
updater::Union{Function, AbstractUpdater}
data::Vector{<:AbstractData}
time::Bool
condition
is a function that takes the state and returns a boolean. If condition(state) == false
, the operator will not be executed. Ex: always
, first_gen
retriever
is a function/object that takes the state and the operator and returns an object or list of objects to operate on. Should not update state. Ex: get_individuals
, PopulationRetriever
operator
is a function that takes the state and the retrieved object(s) and returns the modified object(s). Should perform none or trivial state updates, like incrementing a counter. Ex: Jevo.make_all_v_all_matches
updater
is a function/object that takes the state and the modified object(s) and updates the state. Ex: ReccordAdder!
, ComputeInteractions!
data
is a vector of data objects that can be stored in the operator. Currently unused.
time
is a boolean that determines if the time taken to execute the operator should be logged. Defaults to false
Jevo.PassThrough
— Typestruct PassThrough <: AbstractCreator
creator::AbstractCreator
end
A PassThrough is a struct that contains a creator to create. When the first create call is made, say on a population, the passthrough creator will return the creator, instead of actually performing the creation. This allows us to pass through genotype creators and developers to instantiated populations without creating them.
Jevo.Performer
— Type Performer <: AbstractOperator
Runs all matches in state.matches, and adds interactions to the individuals in the matches. This operator is intended to be used after a MatchMaker has created matches.
Jevo.PopSizeAssertor
— TypePopSizeAssertor(size::Int, pop_ids::Vector{String}=String[];kwargs...)
Asserts each population with an id
in pop_ids
has size
individuals.
Jevo.Population
— TypePopulation(id::String, individuals::Vector{<:AbstractIndividual})
Create a population with a given id and individuals.
Population(id::String, individuals::Vector{<:AbstractIndividual}) =
Create pop with predefined inds and no data
Jevo.PopulationAdder!
— TypePopulationAdder!()
Creates an Updater that adds populations to the state.
Jevo.PopulationCreatorRetriever
— TypeRetreives all creators of type AbstractPopulation from state.creators
Jevo.PopulationRetriever
— TypeRetrieves Vector{Vector{AbstractIndividual}} from state
For example, a two-pop all vs all matchmaker with the following population hierarchy:
ecosystem
├── composite1
│ ├── pop1a: ind1a1, ind1a2
│ └── pop1b: ind1b1, ind1b2
└── composite2
├── pop2a: ind2a1, ind2a2
└── pop2b: ind2b1, ind2b2
ids = ["ecosystem"] or [] will fetch: [inds1a1, ind1a2, ind1b1, ind1b2, ind2a1, ind2a2, ind2b1, ind2b2]]
ids = ["composite1"] will fetch: [ind1a1, ind1a2, ind1b1, ind1b2]]
ids = ["pop1a"] will fetch: [[ind1a1, ind1a2]]
Jevo.PopulationRetriever
— MethodTraverses the population tree and returns references to all vectors of individuals to an arbitrary depth. If ids is not empty, it only returns individuals from the specified populations
Jevo.PopulationUpdater!
— TypePopulationUpdater!(;ids=String[])
Currently unimplemented.
Jevo.PurgePhylogeny
— TypePurgePhylogeny(ids::Vector{String}=String[];kwargs...)
Purges the phylogenetic tree for populations with ids in ids
. Removes individuals from the phylogenetic tree that with no living descendants.
See also LogPhylogeny, InitializePhylogeny, UpdatePhylogeny
Jevo.RandomEvaluator
— TypeRandomEvaluator(ids::Vector{String}=String[]; kwargs...)
Operator that record with a random fitness score to each individual in populations with ids in ids
. Typically used for testing.
Jevo.ReccordAdder!
— TypeReccordAdder!(;ids=String[])
Creates an Updater that adds records to individuals in populations with ids in ids
.
function(adder::ReccordAdder!)(state::AbstractState, records::Vector{<:Vector{<:Vector{<:AbstractRecord}}})
Jevo.Reporter
— TypeReporter(;kwargs...)
Reporter(type::Type{<:AbstractMetric}; h5=true, txt=true, console=false, kwargs...)
Operator that "reports" some aspect of the state to either the console, a text file, or an hdf5 file. Allows us to log or record data anywhere in the pipeline.
Jevo.ScalarFitnessEvaluator
— TypeScalarFitnessEvaluator(ids::Vector{String}=String[]; kwargs...)
Operator that computes the scalar fitness of each individual in populations with ids in ids
. Requires all individuals to have at least one interaction.
The scalar fitness is the mean of the scores of each interaction, shifted by the minimum score.
Jevo.SoloMatchMaker
— TypeJevo.State
— Typemutable struct State <: AbstractState
id::String
rng::AbstractRNG
creators::Vector{AbstractCreator}
operators::Vector{AbstractOperator}
populations::Vector{AbstractPopulation}
counters::Vector{AbstractCounter}
matches::Vector{AbstractMatch}
data::Vector # for extensions
end
A mutable struct which holds all runtime data for an evolutionary simulation. See [`State(rng::AbstractRNG, creators::Vector{<:AbstractCreator}, operators::Vector{<:AbstractOperator})`](@ref) . each generation.
Example
using Jevo, StableRNGs
rng = StableRNG(1)
k = 1
n_dims = 2
n_inds = 2
n_species = 2
n_gens = 10
counters = default_counters()
ng_genotype_creator = Creator(VectorGenotype, (n=n_dims,rng=rng))
ng_developer = Creator(VectorPhenotype)
comp_pop_creator = Creator(CompositePopulation, ("species", [("p$i", n_inds, ng_genotype_creator, ng_developer) for i in 1:n_species], counters))
env_creator = Creator(CompareOnOne)
state = State("ng_phylogeny", rng,[comp_pop_creator, env_creator],
[InitializeAllPopulations(),
AllVsAllMatchMaker(),
Performer(),
ScalarFitnessEvaluator(),
TruncationSelector(k),
CloneUniformReproducer(n_inds),
Mutator(),
ClearInteractionsAndRecords(),
Reporter(GenotypeSum, console=true)], counters=counters)
run!(state, n_gens)
Jevo.State
— MethodState(
id::String,
rng::AbstractRNG,
creators::Vector{<:AbstractCreator},
operators::Vector{<:AbstractOperator};
counters::Vector{<:AbstractCounter}=default_counters(),
populations::Vector{<:AbstractPopulation}=AbstractPopulation[],
matches::Vector{<:AbstractMatch}=AbstractMatch[],
data::Vector=[],
)
States are created from a random number generator, a list of creators, and a list of operators, and usually a list of counters.
creators
should have at least on population creator and one environment creator. operators
should contain an operator for each step of the evolutionary process. counters
should contain a generation counter, individual id counter, gene counter, and match counter. All creators/operators should refer to the counter objects in state.
Use generation(state)
to get the current generation number, initialized to one. The GenerationIncrementer
operator is automatically appended to the operator list to advance the state to the next generation. Individuals created without any parents are of generation 0.
Jevo.TruncationSelector
— TypeTruncationSelector <: AbstractSelector
Selects the top k individuals from a population based on their fitness scores, purging the rest. The individuals are sorted by their fitness scores in descending order, and the top k individuals are selected. If there are fewer than k individuals in the population, raises an error.
Jevo.UpdateDeltaCache
— TypeUpdateDeltaCache(ids::Vector{String}=String[];kwargs...)
Updates the DeltaCache for a population with the current generation's individuals.
Jevo.UpdateGenePool
— TypeUpdateGenePool(ids::Vector{String}=String[]; after_gen::Int, n_latest::Int, time::Bool=false, kwargs...)
After generation after_gen
, updates the gene pool for populations with ids in ids
with the n_latest
most recent deltas.
Jevo.UpdatePhylogeny
— TypeUpdatePhylogeny(ids::Vector{String}=String[];kwargs...)
Updates the phylogenetic tree for populations with ids in ids
. The tree is updated with the current generation's individuals as children of their parents. If an individual has no parent or more than one parent, an error is thrown.
See also LogPhylogeny, InitializePhylogeny, PurgePhylogeny
Jevo.Weights
— Typestruct Weights <: AbstractWeights
dims::Tuple{Vararg{Int}}
muts::Vector{NetworkGene}
end
A collection of genes which generate a tensor of Float32
when developed. Each gene in muts
is developed into a tensor and added together to form the final tensor. A _WeightCache
can be used to cache intermediate tensors to avoid redundant computation.
Jevo.WeightsCollection
— Typestruct WeightsCollection{T<:AbstractWeights} <: AbstractWeights
dims::Tuple{Vararg{Int}}
weights::Array{T}
end
Concatenation of multiple weight blocks into a single weight tensor, to adjust subsets of weights independently
Base.map!
— Methodmap!(f::Function, x::AbstractLayer)
Apply a function to all weights in a neural network.
Base.show
— MethodOverride Base.show to avoid printing empty containers
Jevo.add_matches!
— Methodadd_matches!(state::AbstractState, matches::Vector{Match})
Updater which adds matches to the state.
Jevo.always
— MethodCondition for operators that should run each generation
Jevo.clone
— Methodclone(state::AbstractState, parent::AbstractIndividual)
Create a child with the same genotype as the parent, but with the id, generation, and parent changed.
Jevo.copyarchitecture
— MethodRecursively makes copy of network architecture without copying the individual genes.
Jevo.create
— Methodcreate(x)
Calls create
on all elements of x
that are creators, and returns x
otherwise. This recursively instantiates all creators. If a creator is enclosed in a PassThrough, the PassThrough wrapper is removed, and the creator is kept as is.
create(::AbstractState, x)
: Calls create(x)
, can be used in an Operator. create(c::AbstractCreator)
: Calls the creator function c
. create(args::Tuple)
: Recursively creates elements of the tuple. create(kwargs::NamedTuple)
: Recursively creates values of the named tuple. create(cs::Vector{<:AbstractCreator})
: Calls create
for each element in the vector of creators. create(x)
: Returns x
if x is not a creator and does not contain a creator
All calls to create
eventually lead, someway or another, to a call to the following constructor
(creator::Creator{T})() where T = T(create(creator.kwargs)...)
which creates the object of type T
with the arguments in creator.kwargs
.
See also: Creator, PassThrough
Jevo.create_op
— Methodcreate_op(
type::Union{Type{<:AbstractOperator}, String};
condition=always,
retriever=noop,
operator=noop,
updater=noop,
data=AbstractData[],
time=false,
additional_fields...
)
Create an Operator of type type
with the specified fields. All fields are optional. The retriever, operator, and updater fields default to noop
.
Jevo.find
— Methodfind(attr::Symbol, match::Any, v::Vector)
Find the first element in v where el.attr == match. Used for finding counters of a specific type.
Jevo.first_gen
— Methodfirst_gen(state::AbstractState)
Return true if the current generation is 1.
Jevo.generation
— Methodgeneration(state::AbstractState)
Return the current generation number of the state stored in the AbstractGeneration
counter.
Jevo.get_counter
— Methodget_counter(type::Type, state::AbstractState)
Returns the counter of the given type in the state.
Jevo.get_individuals
— Methodget_individuals(state::AbstractState, args...)
Jevo.get_opponent_ids_2player
— MethodGet id of other individual in a 2-player match
Jevo.getonly
— Methodgetonly(f, itr::Union{Vector, Tuple})
Returns the only element in itr that satisfies the predicate f. If there are no elements or more than one element, an error is thrown.
Jevo.inc!
— Methodinc!(counter::Counter, n::Int=1)
Increment the value of the given counter
by n
in a thread-safe manner. Returns the value of before the increment.
Jevo.make_all_v_all_matches
— Methodmake_all_v_all_matches(state::AbstractState, pops::Vector{Vector{Population}})
Returns a vector of Matches between all pairs of individuals in the populations.
Jevo.mutate!
— Methodmutate!(rng::AbstractRNG, state::AbstractState, population::AbstractPopulation, genotype::AbstractGenotype; kwargs...)
Jevo.noop
— Methodnoop([x...])
Returns the arguments passed
noop(::AbstractState, x)
Returns x. Used to perform no operation for retrievers, operators, and updaters.
Jevo.run!
— Methodrun!(state::State, max_generations::Int)
Begin/continue evolution until generation max_generations
Jevo.skip
— Methodskip iterating over certain hierarchical configurations. We currently use this to
avoid iterating over the embedding weights for both the Embed and EmbedDecoder layers.
Jevo.verify_weights_collection
— MethodConfirms that each row of weights has the same # of rows in each weight, and each column has the same number of columns.
Jevo.@define_op
— Macro@define_op name [supertype=AbstractOperator, additional_fields=""]
Defines a a subtype of supertype
called name
with the following fields:
condition
retriever
operator
updater
data
time
See Operator
for more information.
Example
@define_op "AllVsAllMatchMaker" "AbstractMatchMaker"