Neat
Documentation for Neat.
Neat.NeatConfig.DEFAULT_CONFIG
Neat.CreateGenome.create_genome
Neat.CreateGenome.next_genome_id
Neat.CreateGenome.reset_genome_id!
Neat.Crossover.crossover
Neat.Fitness.evaluate_fitness
Neat.ForwardPass.forward_pass
Neat.ForwardPass.topological_sort
Neat.Innovation.get_innovation_number
Neat.Innovation.reset_innovation_counter!
Neat.Mutation.add_connection!
Neat.Mutation.add_node!
Neat.Mutation.causes_cycle
Neat.Mutation.mutate
Neat.Mutation.mutate_weights!
Neat.NeatConfig._default_toml_path
Neat.NeatConfig.load_config
Neat.Population.initialize_population
Neat.Speciation.adjust_fitness!
Neat.Speciation.assign_species!
Neat.Speciation.compatibility_distance
Neat.Speciation.compute_offspring_counts
Neat.Speciation.select_elites
Neat.Visualize.plot_fitness_history
Neat.NeatConfig.DEFAULT_CONFIG
— ConstantDEFAULT_CONFIG :: Dict{String,Any}
A Dict specifying default settings for population, mutation, crossover, and speciation.
Neat.NeatConfig._default_toml_path
— Methoddefaulttoml_path() -> String
Return the file path for the TOML configuration file (neat_config.toml
) in the current working directory.
Neat.NeatConfig.load_config
— Methodload_config() -> Dict{String,Any}
Load the configuration from neat_config.toml
. If the file does not exist, write the DEFAULT_CONFIG to that file first, then parse and return it. If the file exists, log that the existing configuration is being used.
Neat.CreateGenome.create_genome
— Methodcreate_genome(num_inputs::Int, num_outputs::Int) → Genome
Creates a Genome
with:
- The specified number of input nodes
- The specified number of output nodes
- Fully connected input-to-output connections with random weights
NO HIDDEN NODES ARE CREATED INITIALLY
Arguments
num_inputs::Int
: Number of input nodes.num_outputs::Int
: Number of output nodes.
Returns
Genome
: A new genome with nodes and fully connected input-output links.
Neat.CreateGenome.next_genome_id
— Methodnext_genome_id() → Int
Returns the next global node id.
Neat.CreateGenome.reset_genome_id!
— Methodreset_id!()
Resets the counter (useful for tests).
Neat.Fitness.evaluate_fitness
— Methodevaluate_fitness(genome::Genome; ds_name::Union{String,Missing}=missing) -> Float64
Compute the fitness of a genome
on a specified dataset by running its neural network and summing the squared errors between outputs and targets, then returning the negative total error.
A more positive return value indicates better performance (lower overall error).
Keyword Arguments
genome
: TheGenome
whose network will be evaluated.ds_name
: Optional name of the dataset to use (e.g.,"XOR_DATA"
or"PARITY3_DATA"
). If not defined, the defaulttraining_data
key from the configuration is used.
Returns
Float64
: Negative sum of squared errors over all input–target pairs in the dataset.
Neat.ForwardPass.forward_pass
— Methodforward_pass(genome::Genome, input::Vector{Float64}) → Dict{Int, Float64}
Performs a forward pass through the network defined by genome
, computing activation values for all nodes.
Arguments
genome::Genome
: The genome containing nodes and connections.input::Vector{Float64}
: Activation values for input nodes.
Returns
Dict{Int, Float64}
: A dictionary mapping each node ID to its activation value.
Neat.ForwardPass.topological_sort
— Methodtopological_sort(genome::Genome) → Vector{Int}
Performs a topological sort of all nodes in the genome
. The resulting order ensures each node appears only after all its predecessors have been processed.
Arguments
genome::Genome
: The genome containing nodes and connections.
Returns
Vector{Int}
: A list of node IDs in a valid computation order.Vector{Connection}
: A list of all enabled connections in the genome.
Errors
- Throws an error if the graph contains cycles, making topological sorting impossible.
Neat.Mutation.add_connection!
— Methodadd_connection!(genome::Genome; max_attempts::Int=50) -> Nothing
Try up to max_attempts
times to add a new connection between two previously unconnected nodes without creating a cycle.
Selects random input and output nodes (skipping invalid or existing edges) until a valid pair is found or attempts exhausted.
Keyword Arguments
max_attempts
: Maximum number of trials before giving up (default: 50).
Neat.Mutation.add_node!
— Methodadd_node!(genome::Genome) -> Nothing
Insert a new hidden node by splitting an existing enabled connection.
- Chooses a random enabled connection A → B and disables it.
- Creates a new hidden node C with a unique ID.
- Adds two connections: A → C (weight = 1.0) and C → B (weight equal to the original connection).
This mutation allows the network topology to grow.
Arguments
genome
: TheGenome
to modify.
Neat.Mutation.causes_cycle
— Methodcauses_cycle(genome::Genome, src_id::Int, dst_id::Int) -> Bool
Determine whether adding a connection from node src_id
to dst_id
would introduce a cycle.
Performs a depth-first search starting from dst_id
to see if src_id
is reachable.
Arguments
genome
: TheGenome
whose topology is checked.src_id
: Identifier of the potential source node.dst_id
: Identifier of the potential destination node.
Returns
true
if a path exists fromdst_id
back tosrc_id
(a cycle would form), otherwisefalse
.
Neat.Mutation.mutate
— Methodmutate(genome::Genome; perturb_chance, sigma, add_connection_prob, node_add_prob, max_attempts) -> Nothing
Apply a full suite of mutation operators to genome
according to configured probabilities.
- Weight mutations via
mutate_weights!
. - With probability
add_connection_prob
, attemptadd_connection!
. - With probability
node_add_prob
, attemptadd_node!
.
If any probability or max_attempts
is not defined, the value is loaded from the mutation
section of the configuration.
Keyword Arguments
perturb_chance
: Probability for weight perturbation.sigma
: Stddev for weight perturbation.add_connection_prob
: Chance to add a new connection.node_add_prob
: Chance to add a new node.max_attempts
: Max trials for adding a connection.
Neat.Mutation.mutate_weights!
— Methodmutate_weights!(genome::Genome; perturb_chance::Float64, sigma::Float64) -> Nothing
Apply weight mutations to all connections of genome
by replacing each with a new modified connection.
- With probability
perturb_chance
, add a perturbation drawn fromNormal(0, sigma)
. - Otherwise, assign a completely new weight sampled from
Normal(0, 1)
.
Arguments
genome
: TheGenome
whose connection weights will be mutated.perturb_chance
: Probability of choosing a small perturbation over full replacement.sigma
: Standard deviation of the Gaussian perturbation.
Neat.Population.initialize_population
— Methodinitialize_population(num_genomes::Int, num_inputs::Int, num_outputs::Int) → Vector{Genome}
Create a population of n
genomes initialized with given number of input/output nodes. Each genome is assigned a unique ID.
Arguments
num_genomes
: Number of genomes to create.num_inputs
: Number of input nodes.num_outputs
: Number of output nodes.
Returns
- A vector of
Genome
objects.
Neat.Crossover.crossover
— Functioncrossover(parent1::Genome, parent2::Genome) → Genome
Perform crossover between two parent genomes. The fitter parent contributes all disjoint and excess genes. Matching genes are randomly inherited from either parent. Disabled genes may remain disabled in the child.
Arguments
parent1::Genome
: One parent genome.parent2::Genome
: Another parent genome.
Returns
Genome
: A new child genome composed from both parents' genes.
Neat.Speciation.adjust_fitness!
— Methodadjust_fitness!(species_list::Vector{Vector{Genome}})
Applies fitness sharing to scale each genome’s fitness relative to its species size.
Modifies each genome's fitness value in-place by applying NEAT-style fitness sharing:
- Divides each genome's fitness by the number of members in its species.
Arguments
species_list
: A vector of species (each a vector of genomes).
Side Effects
- Sets each genome’s
adjusted_fitness
tofitness / species_size
.
Neat.Speciation.assign_species!
— Methodassign_species!(population::Vector{Genome}, species_list::Vector{Vector{Genome}}; speciation_threshold::Union{Float64,Missing}=missing, c1::Union{Float64,Missing}=missing, c2::Union{Float64,Missing}=missing, c3::Union{Float64,Missing}=missing)
Divide a population of genomes into species based on compatibility distance.
For each genome (in random order), compute its distance to the representative of each existing species (the first member). If the smallest distance is ≤ speciation_threshold
, add it to that species; otherwise, start a new species with this genome as its representative.
If speciation_threshold
, c1
, c2
, or c3
is missing
, the corresponding value is loaded from the training parameters in the configuration.
Arguments
population
: Vector of genomes to classify.species_list
: Vector of species (each a vector of genomes) to populate.speciation_threshold
: Maximum compatibility distance to join an existing species.c1
,c2
,c3
: Coefficients forwarded tocompatibility_distance
.
Side Effects
- Clears and reassigns
species_list
in-place.
Neat.Speciation.compatibility_distance
— Methodcompatibility_distance(g1::Genome, g2::Genome; c1::Union{Float64,Missing}=missing, c2::Union{Float64,Missing}=missing, c3::Union{Float64,Missing}=missing) -> Float64
Compute the NEAT compatibility distance between two genomes:
δ = (c1 * E / N) + (c2 * D / N) + (c3 * W)
where
E
is the number of excess genes,D
is the number of disjoint genes,W
is the average weight difference of matching genes,N
is the number of genes in the larger genome (treated as 1 if small for stability).
If any of c1
, c2
, or c3
is not defined, its value is loaded from the speciation section of the configuration.
Arguments
g1
,g2
: The twoGenome
instances to compare.c1
: Coefficient for excess genes.c2
: Coefficient for disjoint genes.c3
: Coefficient for average weight differences.
Returns
Float64
: The compatibility distance (lower means more similar).
Neat.Speciation.compute_offspring_counts
— Functioncompute_offspring_counts(species_list::Vector{Vector{Genome}}, population_size::Int=300) -> Vector{Int}
Allocate the total number of offspring among species proportionally to their total adjusted fitness.
Arguments
species_list
: List of species (each a vector of genomes).population_size
: Total number of offspring to distribute.
Returns
- A vector of integers indicating the offspring count for each species (in the same order).
Neat.Speciation.select_elites
— Methodselect_elites(species::Vector{T}, elite_frac::Float64) where {T}
Select the top-performing genomes in a species based on adjusted fitness.
Arguments
species
: Vector of genomes (each with anadjusted_fitness
field).elite_frac
: Fraction of the species to keep as elites (e.g., 0.1 for 10%).
Returns
- A vector of the top
ceil(elite_frac * length(species))
genomes, sorted by descendingadjusted_fitness
.
Neat.Innovation.get_innovation_number
— MethodReturns a unique innovation number for the connection from in_node
to out_node
. If this connection has been seen before, returns the previously assigned number. Otherwise, assigns a new innovation number and stores it. Used in NEAT to track structural mutations consistently across genomes. !Ensures that even if two genomes both add a connection from node A → B, they will NOT get different innovation numbers.
Returns
Int
: The innovation number for the (innode, outnode) pair.
Neat.Innovation.reset_innovation_counter!
— Methodreset_innovation_counter!()
Resets the counter (useful for tests).
Neat.Visualize.plot_fitness_history
— Methodplot_fitness_history(best_fitness_history; filename="fitness_history.png")
Create and save a line plot of the best fitness values over generations.
Arguments
best_fitness_history::Vector{Float64}
: History of best fitness per generation.filename::String
: Output file path (defaults to "fitness_history.png").