nucleotide

package module
v0.9.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 31, 2026 License: BSD-3-Clause Imports: 11 Imported by: 0

README

Nucleotide

Nucleotide is a highly modular and type-safe Genetic Algorithm (GA) framework for Go, designed to evolve complex behaviors and parameters for software agents and simulations.

It introduces the concept of Categorical Genomes, where evolution doesn't just tune numbers, but selects specific behaviors (functions) and configurations that can be directly executed in a simulated or real-world environment.

Key Features

  • Generic Environments ([E any]): Pass any type (Database connections, World simulations, API clients) directly to your genes.
  • Typed Loci Architecture:
    • Behavioral: Genes that execute logic via callbacks.
    • Parameter: Genes that provide data values for behavioral genes.
    • Configuration: Internal framework settings that can themselves be evolved.
    • Sequence: Slots that define a permutation range to evolve orderings, routing sequences, or schedules.
  • Multi-Chromosomal Genomes (CompositeGenome): Map multiple distinct chromosomes by name to evolve complex combinations of behavioral categorical genes, configurations, and independent sequences simultaneously.
  • Permutation Optimization (SequenceGenome): Native support for permutation sequence evolution powered by Partially Mapped Crossover (PMX) and Swap Mutation to guarantee duplicate-free evolution.
  • Unified Robust Serialization: Save any winning genome (BitGenome, FloatGenome, SequenceGenome, CategoricalGenome, CompositeGenome) to JSON using stable IDs, and reload them seamlessly in production.
  • Context-Aware Expression: Execute evolved individuals with context.Context for safe cancellation and timeouts.
  • Modern Go: Built with Go 1.22+ and fully leverages Generics.

Core Concepts: Loci vs. Genes

[!NOTE] Loci (pronounced lo-sigh) is the plural form of Locus. Throughout the library and documentation, we use Locus when referring to a single slot, and Loci when referring to multiple slots.

To understand Nucleotide, it's essential to distinguish between a Locus and a Gene:

The Biological Analogy

Imagine the trait for Eye Color.

  • The Locus is the specific position on a chromosome that determines eye color. Every human has this "slot".
  • The Gene (or allele) is the specific version occupying that slot—such as Blue, Brown, or Green.
The Software Analogy

In a software system, imagine a Sorting Strategy:

  • The Locus is the abstract "Sorting" component in your architecture.
  • The Genes are the concrete implementations you can plug in: QuickSort, MergeSort, or HeapSort.

Evolution in Nucleotide works by testing which Gene performs best at each Locus given a specific environment.

Advanced Dynamics

1. Execution Order

Nucleotide allows the evolution of the order in which genes are expressed. In many systems, the sequence of operations is as critical as the operations themselves. For example, in a processing pipeline, executing ValidateData before SaveToDB is mandatory, but the order of optional Enrichment steps might yield different results depending on environmental constraints (like latency or data availability).

2. Parameterization & Adaptation

Parameter Genes allow a specific algorithm (Gene) to operate differently to best suit its environment.

  • Example: In a K-Means Clustering algorithm, the number of clusters (k) is a critical parameter.
  • A locus could define the "Cluster Count", and evolution would find the optimal k for the current dataset, allowing the same K-Means gene to adapt its behavior without changing its core logic.

Advanced Selection & Evolution Operators

Nucleotide provides a highly customizable operator execution model and advanced selection algorithms to prevent premature convergence and control selection pressure.

1. Multi-Operator Slices & Fallback Defaults

Instead of defining a single crossover or mutation strategy, EngineConfig supports multiple strategies in slices:

  • Crossoverers & Mutators: Slices of strategies that run interchangeably. If empty, Nucleotide supplies smart defaults (DefaultCrossoverer and DefaultMutator) that automatically adjust at runtime to the type of genome being processed (BitGenome, FloatGenome, or CategoricalGenome).
  • Pondered Weights: Use CrossovererWeights and MutatorWeights to configure custom probability distributions for each operator. If weights are omitted, the engine defaults to a smooth, alternating Round-Robin sequencing strategy.
2. Individual Lifetime (Age) Tracking

Individuals track their survival generation span using an Age property, initialized to 0 and automatically incremented at the end of each generation loop in the evolutionary engine. This age metric is used to model life expectancy and introduce biological selection penalties.

3. Core Selection Operators

All custom selectors implement the standard Selector interface:

  • RouletteWheelSelector[E, S]: Proportional fitness selection with optional AutoShift capability to handle negative fitness boundaries.
  • StochasticUniversalSamplingSelector[E, S]: Low-variance, zero-bias multi-pointer selection utilizing a single-spin buffer queue to ensure equal-interval selection across sequential calls.
  • RankSelector[E, S]: Maps absolute fitness values to linear ranks ($1$ to $N$) with customizable SelectionPressure values. Prevents super-individuals from dominating early generations.
  • BoltzmannSelector[E, S]: Standard temperature-scaled selection ($e^{f(x) / T}$) allowing exploration/exploitation weighting across epochs.
4. Advanced GenericTournamentSelector[E, S] Features

The built-in tournament selector can be enhanced using several advanced, fully opt-in dynamics:

  • Adaptive Diversity: Sizing adapts dynamically depending on population standard deviation (reducing tournament size when diversity is low to encourage exploration).
  • Age Bias: A custom penalty applied to competitor fitness proportional to their survival age (adjustedFit = adjustedFit - age * AgeBias) to prevent stagnation.
  • Hall of Fame competitor mixing: Integrates historical elite individuals into active tournaments with a specified HallOfFameProbability to encourage competition.
  • Self-Adaptive Sizing: Individuals can adaptively define their preferred tournament sizing (TournamentSize) through parameter genes or custom state interfaces implementing SelfAdaptiveIndividual.

Multi-Objective Optimization (NSGA-II)

Nucleotide supports Multi-Objective Optimization using the NSGA-II (Nondominated Sorting Genetic Algorithm II) algorithm. This is suitable when you need to optimize conflicting metrics in tension, such as maximizing performance/throughput while minimizing cost/power consumption.

Key NSGA-II Features:
  • Unified Fitness Signature: Fitness is represented as []float64 to transparently scale from single-objective (length 1) to multi-objective environments.
  • Configurable Directions: Define whether to Maximize or Minimize each objective independently via ObjectiveDirections []ObjectiveDirection.
  • Fast Non-Dominated Sorting: Classifies individuals into sequential Pareto frontiers ($F_1, F_2, \dots$) based on mathematical dominance.
  • Crowding Distance & Density Calculation: Scans boundary points and computes sparsity metrics to favor diverse, well-distributed solutions across the Pareto frontier.
  • Crowded Comparison Operator Selection: The GenericTournamentSelector automatically applies rank-based and crowding-distance-based tournament selection when running in multi-objective mode.
  • Pareto Frontier Access: Retrieve the best non-dominated solutions of a finished run via engine.ParetoFrontier().
Code Example:
config := nucleotide.EngineConfig[MyEnv, MyState]{
    PopulationSize: 100,
    MaxGenerations: 50,
    FitnessFunc: func(g nucleotide.Genome, env MyEnv) []float64 {
        // Return multiple fitness scores
        return []float64{performance, cost}
    },
    Selector: nucleotide.GenericTournamentSelector[MyEnv, MyState]{Size: 3},
    
    // Objective 0: Maximize performance
    // Objective 1: Minimize cost
    ObjectiveDirections: []nucleotide.ObjectiveDirection{
        nucleotide.Maximize,
        nucleotide.Minimize,
    },
}

engine, _ := nucleotide.NewEngine(config)
engine.Run(def)

// Retrieve the optimal trade-offs (Rank 0 non-dominated solutions)
paretoFrontier := engine.ParetoFrontier()

Parallel Island Model GA (MultiIslandEngine)

Nucleotide supports the Parallel Island Model Genetic Algorithm via the MultiIslandEngine struct. Instead of evolving a single global population, the population is divided into isolated sub-populations (islands) that evolve independently in parallel in their own goroutines, periodically exchanging individuals (migration epochs) to maintain diversity and prevent premature convergence.

Key Island Model Features:
  • True Concurrency: Sub-populations evolve concurrently on separate Go routine threads, synchronizing at migration epochs using a synchronization barrier (sync.WaitGroup).
  • Flexible Topologies: Configure migration routing using TopologyRing (cyclic neighbor routing) or TopologyRandom (fully connected randomized target routing).
  • Migration Policies: Support PolicyBestReplaceWorst (exploitation-focused: copies best individuals to replace target worst) or PolicyRandomReplaceRandom (exploration-focused).
  • 3 Environment Configurations (Option A, B, and C):
    • Option A (Shared Static Env): All islands share the same single environment (the default).
    • Option B (Distributed Independent Envs): The EnvFactory instantiates independent environment simulator instances to prevent resource contention.
    • Option C (Heterogeneous Envs): The EnvFactory provides specialized configurations per island (e.g. different weather/difficulties), forcing the co-evolution of generalist solutions.
Code Example:
config := nucleotide.EngineConfig[MyEnv, MyState]{
    PopulationSize: 20,
    MaxGenerations: 40,
    FitnessFunc:    myFitnessFunc,
    Selector:       nucleotide.GenericTournamentSelector[MyEnv, MyState]{Size: 3},
}

// Option C: Evolve across heterogeneous climates (Sunny, Windy, Rainy)
envFactory := func(islandIndex int) MyEnv {
    return climates[islandIndex]
}

miConfig := nucleotide.MultiIslandEngineConfig[MyEnv, MyState]{
    NumIslands:        3,
    MigrationInterval: 5, // migrate every 5 generations
    MigrationRate:     2, // move top 2 individuals
    MigrationTopology: nucleotide.TopologyRing,
    MigrationPolicy:   nucleotide.PolicyBestReplaceWorst,
    EngineConfig:      config,
    EnvFactory:        envFactory,
}

miEngine, _ := nucleotide.NewMultiIslandEngine(miConfig)
bestIndividual, _ := miEngine.Run(def)

Installation

go get github.com/rghashimoto/nucleotide

Usage Levels

1. Basic Usage (Optimization)

Ideal for solving classic optimization problems like OneMax or Knapsack using simple bitstring or float genomes.

  • Example: onemax/main.go
  • Goal: Find the bitstring with the maximum number of true values.
2. Structured Usage (Component Selection)

Use Categorical Genomes to select the best combination of components or traits for an entity.

  • Example: structured/main.go
  • Goal: Evolve an object with the best combination of Color, Size, and Material.
3. Advanced Usage (Behavioral Evolution)

Evolve agents that interact with a dynamic environment. Genes are functions that consume resources or change the state of the world.

  • Example: advanced/main.go
  • Goal: Evolve a survival strategy (Glutton vs. Frugal) in a world with limited food.
4. Multi-Objective Optimization (NSGA-II)

Solve complex problems where multiple conflicting objectives must be optimized simultaneously (e.g. maximizing value while minimizing weight).

  • Example: multiobjective/main.go
  • Goal: Find the non-dominated Pareto Frontier trade-offs for a dual-objective Knapsack problem.
5. Comprehensive Usage (Autonomous Routing & Multi-Chromosomal Evolution)

Co-evolve categorical behaviors, parameters, internal configurations, and sequence delivery routes using name-based multi-chromosomal mapping.

  • Example: comprehensive/main.go
  • Goal: Evolve the optimal drone battery configuration, pre-flight safety actions, sequential execution flow, and customer visitation route order in a unified cargo delivery simulation with round-trip JSON serialization.
6. Parallel Island Model GA (MultiIslandEngine)

Evolve sub-populations in parallel concurrently in separate goroutines, periodically migrating selected individuals to maintain diversity across heterogeneous climates.

  • Example: islands/main.go
  • Goal: Co-evolve a generalist drone dispatcher across three heterogeneous weather climates (Sunny, Windy, and Rainy) using concurrent island routines and ring migration epochs.

Customization & Extensibility

Nucleotide is built to be extended. You can customize almost every aspect of the genetic process by providing your own functions:

Function Type Purpose Usage
FitnessFunc[E] Defines how to score an individual. config.FitnessFunc = myFunc
ElitismFunc[E] Defines which individuals survive to the next generation. config.ElitismFunc = nucleotide.TopNElitism
PopulationFunc[E] Defines how the initial population is created. config.PopulationFunc = myPopFactory
Sequencer[E] Controls the order in which behavioral genes are expressed. Add to "Execution Order" Locus
Gene Callbacks The core logic executed when a gene is expressed. locus.AddGene("ID", myCallback)
Example: Custom Sequencer

You can control the execution flow based on the selected genes:

execLocus.AddConfigGene("MyOrder", func(ctx SequencingContext[E]) []int {
    // Return a custom slice of indices to define the execution order
    return []int{1, 0, 2} 
})

From Evolution to Production

Nucleotide is designed to bridge the gap between AI research and production deployment.

  1. Evolve: Run the Genetic Engine to find the best individual.
  2. Save: Export the genome to a portable JSON file.
    best.Save("production_config.json")
    
  3. Deploy: Load the JSON in your production service and execute it.
    loadedGenome, _ := nucleotide.LoadGenome(prodDef, "production_config.json")
    agent := nucleotide.NewIndividual(loadedGenome)
    agent.Express(ctx, liveEnvironment)
    

License

BSD-3-Clause

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EncodeGenome

func EncodeGenome(g Genome) ([]byte, error)

EncodeGenome encodes a Genome's gene IDs into a JSON byte slice.

func SaveGenome

func SaveGenome(g Genome, filename string) error

SaveGenome saves a Genome's gene IDs to a JSON file.

Types

type AdaptiveMutationController

type AdaptiveMutationController[Env any, State any] interface {
	// GetMutationScaler returns a scaling factor for the mutation rate.
	GetMutationScaler(e *Engine[Env, State]) float64
}

AdaptiveMutationController defines the interface for dynamically scaling or adjusting mutation rates.

type ArithmeticCrossover

type ArithmeticCrossover struct {
	Alpha float64 // weight factor in [0, 1]
}

ArithmeticCrossover performs arithmetic combination of two FloatGenomes.

func (ArithmeticCrossover) Crossover

func (c ArithmeticCrossover) Crossover(p1, p2 Genome) (Genome, Genome)

type BitFlipMutator

type BitFlipMutator struct {
	Probability float64
}

BitFlipMutator flips a bit with a given probability.

func (BitFlipMutator) Mutate

func (m BitFlipMutator) Mutate(g Genome) Genome

type BitGenome

type BitGenome []bool

BitGenome and FloatGenome are kept for compatibility.

func (BitGenome) Copy

func (g BitGenome) Copy() Genome

func (BitGenome) Size

func (g BitGenome) Size() int

type BoltzmannSelector

type BoltzmannSelector[Env any, State any] struct {
	Temperature float64 // Defaults to 1.0 if <= 0
}

BoltzmannSelector selects individuals using a Boltzmann distribution with temperature.

func (BoltzmannSelector[Env, State]) Select

func (s BoltzmannSelector[Env, State]) Select(pop interface{}) interface{}

func (BoltzmannSelector[Env, State]) SelectTyped

func (s BoltzmannSelector[Env, State]) SelectTyped(pop Population[Env, State]) *Individual[Env, State]

type CategoricalCreepMutator

type CategoricalCreepMutator struct {
	Probability float64 // mutation probability per locus
}

CategoricalCreepMutator shifts the selected gene index of CategoricalGenomes to an adjacent option.

func (CategoricalCreepMutator) Mutate

type CategoricalGenome

type CategoricalGenome[Env any, State any] struct {
	Definition  *Definition[Env, State]
	GeneIndices []int
}

CategoricalGenome represents a genome where each locus has a specific gene chosen.

func (*CategoricalGenome[Env, State]) Copy

func (g *CategoricalGenome[Env, State]) Copy() Genome

func (*CategoricalGenome[Env, State]) GetDefinition

func (g *CategoricalGenome[Env, State]) GetDefinition() interface{}

func (*CategoricalGenome[Env, State]) GetGenePairs

func (g *CategoricalGenome[Env, State]) GetGenePairs() []LocusGenePair

func (*CategoricalGenome[Env, State]) GetIndices

func (g *CategoricalGenome[Env, State]) GetIndices() []int

func (*CategoricalGenome[Env, State]) GetLocus

func (g *CategoricalGenome[Env, State]) GetLocus(i int) (int, bool, bool)

func (*CategoricalGenome[Env, State]) SetIndices

func (g *CategoricalGenome[Env, State]) SetIndices(indices []int)

func (*CategoricalGenome[Env, State]) Size

func (g *CategoricalGenome[Env, State]) Size() int

type CategoricalMutator

type CategoricalMutator struct {
	Probability float64
}

CategoricalMutator chooses a random gene from the possible genes for a locus.

func (CategoricalMutator) Mutate

func (m CategoricalMutator) Mutate(g Genome) Genome

type CompositeGenome

type CompositeGenome map[string]Genome

CompositeGenome represents a multi-chromosomal genome mapped by name.

func (CompositeGenome) Copy

func (g CompositeGenome) Copy() Genome

func (CompositeGenome) Size

func (g CompositeGenome) Size() int

type Context

type Context[Env any, State any] struct {
	Ctx        context.Context
	Individual *Individual[Env, State]
	Env        Env
}

Context provides access to the individual's state and the environment during expression.

type Crossoverer

type Crossoverer interface {
	Crossover(p1, p2 Genome) (Genome, Genome)
}

Crossoverer defines the interface for combining two parents into offspring.

type CycleCrossover

type CycleCrossover struct{}

CycleCrossover performs Cycle Crossover (CX) on two SequenceGenomes, preserving absolute position mappings.

func (CycleCrossover) Crossover

func (c CycleCrossover) Crossover(p1, p2 Genome) (Genome, Genome)

Crossover implements the Crossoverer interface, delegating composite genomes automatically.

type DefaultCrossoverer

type DefaultCrossoverer struct{}

DefaultCrossoverer performs dynamic fallback crossover based on genome type.

func (DefaultCrossoverer) Crossover

func (c DefaultCrossoverer) Crossover(p1, p2 Genome) (Genome, Genome)

type DefaultMutator

type DefaultMutator struct {
	Probability float64
}

DefaultMutator performs dynamic fallback mutation based on genome type.

func (DefaultMutator) Mutate

func (m DefaultMutator) Mutate(g Genome) Genome

type Definition

type Definition[Env any, State any] struct {
	Loci []*Locus[Env, State]
}

Definition defines the structure of the genome (the set of loci). Note: "Loci" is the plural form of "Locus".

func NewDefinition

func NewDefinition[Env any, State any]() *Definition[Env, State]

NewDefinition creates a new definition with default configuration loci.

func (*Definition[Env, State]) AddLocus

func (d *Definition[Env, State]) AddLocus(id string, lType LocusType) *Locus[Env, State]

AddLocus adds a new locus to the definition.

func (*Definition[Env, State]) AddSequenceGene

func (d *Definition[Env, State]) AddSequenceGene(id string, min, max int)

AddSequenceGene on Definition adds a sequence gene configuration to the last added locus.

type EdgeRecombinationCrossover

type EdgeRecombinationCrossover struct{}

EdgeRecombinationCrossover performs Edge Recombination Crossover (ERX) on two SequenceGenomes, preserving path linkages.

func (EdgeRecombinationCrossover) Crossover

func (c EdgeRecombinationCrossover) Crossover(p1, p2 Genome) (Genome, Genome)

Crossover implements the Crossoverer interface, delegating composite genomes automatically.

type ElitismFunc

type ElitismFunc[Env any, State any] func(pop Population[Env, State], size int) Population[Env, State]

ElitismFunc defines the strategy for carrying over individuals to the next generation.

type Engine

type Engine[Env any, State any] struct {
	Config     EngineConfig[Env, State]
	Population Population[Env, State]
	Generation int

	DiversityHistory    []float64
	SuccessfulMutations int
	TotalMutations      int
	// contains filtered or unexported fields
}

Engine orchestrates the genetic algorithm process.

func NewEngine

func NewEngine[Env any, State any](config EngineConfig[Env, State]) (*Engine[Env, State], error)

NewEngine creates a new evolution engine and performs validation.

func (*Engine[Env, State]) ParetoFrontier

func (e *Engine[Env, State]) ParetoFrontier() Population[Env, State]

ParetoFrontier returns all non-dominated individuals from the current population (Rank == 0).

func (*Engine[Env, State]) Run

func (e *Engine[Env, State]) Run(def *Definition[Env, State]) (*Individual[Env, State], error)

Run executes the genetic algorithm. It uses the provided definition to initialize the population if not already set.

func (*Engine[Env, State]) Step

func (e *Engine[Env, State]) Step(def *Definition[Env, State]) error

Step executes a single evolutionary generation. It initializes the population if it's not already set.

type EngineConfig

type EngineConfig[Env any, State any] struct {
	PopulationSize      int
	MaxGenerations      int
	FitnessFunc         FitnessFunc[Env, State]
	Selector            Selector
	Crossoverers        []WeightedCrossoverer
	Mutators            []WeightedMutator
	Elitism             int
	ElitismFunc         ElitismFunc[Env, State]
	PopulationFunc      PopulationFunc[Env, State]
	Env                 Env
	ObjectiveDirections []ObjectiveDirection
	Strategy            GenerationStrategy[Env, State]

	// Adaptive Mutation configuration
	AdaptiveMutation   bool
	MaxMutationScaler  float64
	OnMutationAdapted  func(generation int, diversity float64, currentScaler float64)
	MutationController AdaptiveMutationController[Env, State]

	// Age-Biased Mutation configuration
	AgeBiasedMutation    bool
	AgeMutationThreshold int
	AgeMutationScaler    float64

	// Concurrency settings
	ConcurrencyLimit            int
	DisableParallelFitness      bool
	DisableParallelReproduction bool

	//Logging and debugging
	Verbose bool
}

EngineConfig holds the configuration for the evolution engine.

type ExponentialRankSelector

type ExponentialRankSelector[Env any, State any] struct {
	C float64 // Base parameter 'c' in (0.0, 1.0) (defaults to 0.95)
}

ExponentialRankSelector selects individuals based on an exponentially decaying rank.

func (ExponentialRankSelector[Env, State]) Select

func (s ExponentialRankSelector[Env, State]) Select(pop interface{}) interface{}

Select implements the Selector interface.

func (ExponentialRankSelector[Env, State]) SelectTyped

func (s ExponentialRankSelector[Env, State]) SelectTyped(pop Population[Env, State]) *Individual[Env, State]

SelectTyped performs type-safe selection based on exponential rank.

type FitnessFunc

type FitnessFunc[Env any, State any] func(g Genome, env Env) []float64

FitnessFunc defines how to evaluate an individual's fitness across one or more objectives, with access to the environment.

type FloatGenome

type FloatGenome []float64

func (FloatGenome) Copy

func (g FloatGenome) Copy() Genome

func (FloatGenome) Size

func (g FloatGenome) Size() int

type GaussianMutator

type GaussianMutator struct {
	Probability float64 // mutation probability per gene
	StdDev      float64 // standard deviation of the Gaussian noise
}

GaussianMutator adds Gaussian distributed noise to FloatGenomes.

func (GaussianMutator) Mutate

func (m GaussianMutator) Mutate(g Genome) Genome

type Gene

type Gene[Env any, State any] struct {
	ID       string
	Callback func(ctx Context[Env, State])
	Value    interface{}
}

Gene represents an allele at a specific locus.

type GenerationEndHook

type GenerationEndHook[Env any, State any] interface {
	OnGenerationEnd(generation int, pop Population[Env, State])
}

GenerationEndHook allows environments to execute custom logic (such as resource regeneration) at the end of each generation.

type GenerationStartHook

type GenerationStartHook[Env any, State any] interface {
	OnGenerationStart(generation int, pop Population[Env, State])
}

GenerationStartHook allows environments to execute custom logic at the start of each generation.

type GenerationStrategy

type GenerationStrategy[Env any, State any] interface {
	Initialize(e *Engine[Env, State]) error
	NextGeneration(e *Engine[Env, State], def *Definition[Env, State], current Population[Env, State]) (Population[Env, State], error)
}

GenerationStrategy defines a modular execution interface for evolutionary generation loops.

type GenericTournamentSelector

type GenericTournamentSelector[Env any, State any] struct {
	Size int

	// Probabilistic Selection
	Probability float64 // If > 0 and < 1.0, active. Best competitor has chance P, next has P*(1-P), etc.

	// Adaptive Selection
	MinSize            int
	MaxSize            int
	GenerationProgress func() float64 // Function returning fraction [0.0, 1.0] representing run progress.

	// Niching / Local Fitness Sharing
	SigmaShare   float64                     // Niching niche radius (active if > 0)
	NichingAlpha float64                     // Sharing power factor (defaults to 1.0 if <= 0)
	DistanceFunc func(g1, g2 Genome) float64 // Optional custom distance metric.

	// Unique Tournament
	Unique bool // If true, selects competitors without replacement.

	// Diversity-based Adaptive Sizing
	AdaptiveDiversity bool

	// Age-biased Selection
	AgeBias float64

	// Hall of Fame Competitor Integration
	HallOfFame            *Population[Env, State]
	HallOfFameProbability float64

	// Self-adaptive Selection
	SelfAdaptive bool
}

GenericTournamentSelector is a type-safe selector for a specific environment Env and state State.

func NewAdaptiveTournamentSelector

func NewAdaptiveTournamentSelector[Env any, State any](minSize, maxSize int, progressFunc func() float64) GenericTournamentSelector[Env, State]

NewAdaptiveTournamentSelector creates a selector that dynamically scales tournament size.

func NewNichingTournamentSelector

func NewNichingTournamentSelector[Env any, State any](size int, sigma float64, distFunc func(g1, g2 Genome) float64) GenericTournamentSelector[Env, State]

NewNichingTournamentSelector creates a selector that applies local fitness sharing within tournaments.

func NewProbabilisticTournamentSelector

func NewProbabilisticTournamentSelector[Env any, State any](size int, probability float64) GenericTournamentSelector[Env, State]

NewProbabilisticTournamentSelector creates a tournament selector with selection probability controls.

func NewUniqueTournamentSelector

func NewUniqueTournamentSelector[Env any, State any](size int) GenericTournamentSelector[Env, State]

NewUniqueTournamentSelector creates a selector that draws tournament competitors without replacement.

func (GenericTournamentSelector[Env, State]) DetermineTournamentSize

func (s GenericTournamentSelector[Env, State]) DetermineTournamentSize(pop Population[Env, State]) int

Determine effective size (Adaptive Tournament & Diversity-based Sizing)

func (GenericTournamentSelector[Env, State]) Select

func (s GenericTournamentSelector[Env, State]) Select(pop interface{}) interface{}

func (GenericTournamentSelector[Env, State]) SelectTyped

func (s GenericTournamentSelector[Env, State]) SelectTyped(pop Population[Env, State]) *Individual[Env, State]

func (GenericTournamentSelector[Env, State]) SelfAdaptiveSelectionSizeOverride

func (s GenericTournamentSelector[Env, State]) SelfAdaptiveSelectionSizeOverride(pop Population[Env, State]) (Population[Env, State], int)

type Genome

type Genome interface {
	Size() int
	Copy() Genome
}

Genome represents the genetic material of an individual.

func DecodeGenome

func DecodeGenome[Env any, State any](def *Definition[Env, State], data []byte) (Genome, error)

DecodeGenome decodes gene IDs from a JSON byte slice and maps them to indices in the provided Definition.

func LoadGenome

func LoadGenome[Env any, State any](def *Definition[Env, State], filename string) (Genome, error)

LoadGenome loads gene IDs from a JSON file and maps them to indices in the provided Definition.

type GenomeData

type GenomeData struct {
	Type      string                    `json:"type,omitempty"`
	Genes     []LocusGenePair           `json:"genes,omitempty"`
	Sequences map[string]SequenceGenome `json:"sequences,omitempty"`
	Bits      BitGenome                 `json:"bits,omitempty"`
	Floats    FloatGenome               `json:"floats,omitempty"`
	Sequence  SequenceGenome            `json:"sequence,omitempty"`
}

GenomeData is the serializable format of any Genome.

type Individual

type Individual[Env any, State any] struct {
	Genome           Genome
	Fitness          []float64
	State            State
	Age              int
	Rank             int
	CrowdingDistance float64
	MutationRate     float64   // Individual-specific mutation rate (self-adaptation)
	ParentFitness    []float64 // Fitness slice of the best parent for tracking success
}

Individual represents a candidate solution in the population.

func NewIndividual

func NewIndividual[Env any, State any](genome Genome) *Individual[Env, State]

NewIndividual creates a new individual with the given genome.

func (*Individual[Env, State]) Express

func (ind *Individual[Env, State]) Express(ctx context.Context, env Env)

Express executes the behavioral genes based on the configuration loci, with access to the environment and a cancellable context.

func (*Individual[Env, State]) GetParameter

func (ind *Individual[Env, State]) GetParameter(locusID string) interface{}

GetParameter returns the value of a parameter gene at a specific locus ID.

func (*Individual[Env, State]) GetSequence

func (ind *Individual[Env, State]) GetSequence(locusID string) SequenceGenome

GetSequence returns the SequenceGenome at a specific locus ID.

func (*Individual[Env, State]) Save

func (ind *Individual[Env, State]) Save(filename string) error

Save saves the individual's genome to a JSON file.

func (*Individual[Env, State]) ToJSON

func (ind *Individual[Env, State]) ToJSON() ([]byte, error)

ToJSON encodes the individual's genome to a JSON byte slice.

type LinearRankSelector

type LinearRankSelector[Env any, State any] struct {
	SelectionPressure float64 // Selection pressure parameter 's' in [1.0, 2.0] (defaults to 1.5)
}

LinearRankSelector selects individuals based on their sorted rank probability.

func (LinearRankSelector[Env, State]) Select

func (s LinearRankSelector[Env, State]) Select(pop interface{}) interface{}

Select implements the Selector interface.

func (LinearRankSelector[Env, State]) SelectTyped

func (s LinearRankSelector[Env, State]) SelectTyped(pop Population[Env, State]) *Individual[Env, State]

SelectTyped performs type-safe selection based on linear rank.

type Locus

type Locus[Env any, State any] struct {
	ID            string
	Type          LocusType
	Immutable     bool
	PossibleGenes []Gene[Env, State]
	SeqMin        int
	SeqMax        int
}

Locus represents a specific position in the genome. Note: "Loci" (pronounced lo-sigh) is the plural form of "Locus".

func (*Locus[Env, State]) AddConfigGene

func (l *Locus[Env, State]) AddConfigGene(id string, value interface{})

AddConfigGene adds a gene for framework configuration.

func (*Locus[Env, State]) AddGene

func (l *Locus[Env, State]) AddGene(id string, callback func(ctx Context[Env, State]))

AddGene adds a possible gene to the locus.

func (*Locus[Env, State]) AddParameterGene

func (l *Locus[Env, State]) AddParameterGene(id string, value interface{})

AddParameterGene adds a gene that holds a value.

func (*Locus[Env, State]) AddSequenceGene

func (l *Locus[Env, State]) AddSequenceGene(id string, min, max int)

AddSequenceGene configures the sequence range.

type LocusGenePair

type LocusGenePair struct {
	LocusID string `json:"locus_id"`
	GeneID  string `json:"gene_id"`
}

LocusGenePair maps a Locus ID to a selected Gene ID.

type LocusType

type LocusType int

LocusType defines the purpose of a locus.

const (
	LocusBehavioral LocusType = iota
	LocusParameter
	LocusConfig
	LocusSequence
)

type MigrationPolicy

type MigrationPolicy int

MigrationPolicy defines which individuals migrate and who they replace.

const (
	PolicyBestReplaceWorst MigrationPolicy = iota
	PolicyRandomReplaceRandom
)

type MigrationTopology

type MigrationTopology int

MigrationTopology defines how migrants are routed between islands.

const (
	TopologyRing MigrationTopology = iota
	TopologyRandom
	TopologyTorus
	TopologyHypercube
	TopologyStar
)

type MultiIslandEngine

type MultiIslandEngine[Env any, State any] struct {
	Config  MultiIslandEngineConfig[Env, State]
	Islands []*Engine[Env, State]
}

MultiIslandEngine orchestrates a parallel island model genetic algorithm.

func NewMultiIslandEngine

func NewMultiIslandEngine[Env any, State any](config MultiIslandEngineConfig[Env, State]) (*MultiIslandEngine[Env, State], error)

NewMultiIslandEngine instantiates a MultiIslandEngine.

func (*MultiIslandEngine[Env, State]) Run

func (m *MultiIslandEngine[Env, State]) Run(def *Definition[Env, State]) (*Individual[Env, State], error)

Run executes the parallel island evolution.

type MultiIslandEngineConfig

type MultiIslandEngineConfig[Env any, State any] struct {
	NumIslands        int
	MigrationInterval int
	MigrationRate     int
	MigrationTopology MigrationTopology
	MigrationPolicy   MigrationPolicy

	EngineConfig EngineConfig[Env, State]
	EnvFactory   func(islandIndex int) Env
}

MultiIslandEngineConfig holds settings for MultiIslandEngine.

type MutationScheduleType

type MutationScheduleType int

MutationScheduleType defines the supported temporal schedules.

const (
	// ScheduleExponentialDecay continuously decays the mutation rate.
	ScheduleExponentialDecay MutationScheduleType = iota
	// ScheduleCosineAnnealing cycles the mutation rate using cosine curves.
	ScheduleCosineAnnealing
)

type Mutator

type Mutator interface {
	Mutate(g Genome) Genome
}

Mutator defines the interface for introducing random changes to a genome.

type NSGA2Generation

type NSGA2Generation[Env any, State any] struct{}

NSGA2Generation implements the multi-objective Non-dominated Sorting Genetic Algorithm II strategy.

func (*NSGA2Generation[Env, State]) Initialize

func (s *NSGA2Generation[Env, State]) Initialize(e *Engine[Env, State]) error

func (*NSGA2Generation[Env, State]) NextGeneration

func (s *NSGA2Generation[Env, State]) NextGeneration(e *Engine[Env, State], def *Definition[Env, State], current Population[Env, State]) (Population[Env, State], error)

type ObjectiveDirection

type ObjectiveDirection int

ObjectiveDirection represents the optimization direction for a single objective.

const (
	Maximize ObjectiveDirection = iota
	Minimize
)

type OrderCrossover

type OrderCrossover struct{}

OrderCrossover performs Order Crossover (OX) on two SequenceGenomes, preserving duplicate-free permutations.

func (OrderCrossover) Crossover

func (c OrderCrossover) Crossover(p1, p2 Genome) (Genome, Genome)

Crossover implements the Crossoverer interface, delegating composite genomes automatically.

type PMXCrossover

type PMXCrossover struct{}

PMXCrossover performs Partially Mapped Crossover (PMX) on two SequenceGenomes, preserving duplicate-free permutations.

func (PMXCrossover) Crossover

func (c PMXCrossover) Crossover(p1, p2 Genome) (Genome, Genome)

type Population

type Population[Env any, State any] []*Individual[Env, State]

Population is a collection of individuals.

func BestIndividualElitism

func BestIndividualElitism[Env any, State any](pop Population[Env, State], size int) Population[Env, State]

BestIndividualElitism carries over the best individual.

func DefaultPopulationFunc

func DefaultPopulationFunc[Env any, State any](def *Definition[Env, State], size int) Population[Env, State]

DefaultPopulationFunc creates a random population based on the definition.

func TopNElitism

func TopNElitism[Env any, State any](pop Population[Env, State], size int) Population[Env, State]

TopNElitism sorts the population and carries over the top N individuals.

func (Population[Env, State]) AverageFitness

func (p Population[Env, State]) AverageFitness() []float64

AverageFitness returns the average fitness for each objective.

func (Population[Env, State]) Best

func (p Population[Env, State]) Best() *Individual[Env, State]

Best returns the individual with the highest fitness.

type PopulationFunc

type PopulationFunc[Env any, State any] func(def *Definition[Env, State], size int) Population[Env, State]

PopulationFunc is a function that creates an initial population.

type RankSelector

type RankSelector[Env any, State any] struct {
	SelectionPressure float64 // typically in [1.0, 2.0], defaults to 1.5 if <= 0
}

RankSelector selects individuals based on their fitness rank rather than absolute fitness.

func (RankSelector[Env, State]) Select

func (s RankSelector[Env, State]) Select(pop interface{}) interface{}

func (RankSelector[Env, State]) SelectTyped

func (s RankSelector[Env, State]) SelectTyped(pop Population[Env, State]) *Individual[Env, State]

type RechenbergController

type RechenbergController[Env any, State any] struct {
	Interval           int     // Number of generations between adjustments (e.g., 5)
	TargetSuccessRatio float64 // Targeted ratio of successful mutations (default 0.2)
	IncreaseFactor     float64 // Multiplier to increase mutation (default 1.22)
	DecreaseFactor     float64 // Multiplier to decrease mutation (default 0.82)
	MinScaler          float64 // Minimum allowed scaling factor (default 0.1)
	MaxScaler          float64 // Maximum allowed scaling factor (default 5.0)
	// contains filtered or unexported fields
}

RechenbergController adjusts mutation scale based on the ratio of successful mutations.

func NewRechenbergController

func NewRechenbergController[Env any, State any](interval int, targetSuccessRatio float64) *RechenbergController[Env, State]

NewRechenbergController creates a new RechenbergController.

func (*RechenbergController[Env, State]) GetMutationScaler

func (c *RechenbergController[Env, State]) GetMutationScaler(e *Engine[Env, State]) float64

GetMutationScaler checks the success ratio over the interval and scales.

type RouletteWheelSelector

type RouletteWheelSelector[Env any, State any] struct {
	AutoShift bool
}

RouletteWheelSelector selects individuals proportionally to their fitness.

func (RouletteWheelSelector[Env, State]) Select

func (s RouletteWheelSelector[Env, State]) Select(pop interface{}) interface{}

Select implements the Selector interface.

func (RouletteWheelSelector[Env, State]) SelectTyped

func (s RouletteWheelSelector[Env, State]) SelectTyped(pop Population[Env, State]) *Individual[Env, State]

SelectTyped performs type-safe selection using a roulette wheel model.

type Selector

type Selector interface {
	// We use any here because Selector might work with different Individual types.
	// However, usually we want it to be specific.
	// Since Selector is an interface, and Go doesn't support generic methods in interfaces,
	// we have a few options. One is to make Selector generic too.
	Select(pop interface{}) interface{}
}

Selector defines the interface for selecting individuals from a population.

type SelfAdaptiveController

type SelfAdaptiveController[Env any, State any] struct {
	LearningRate float64 // Learning rate tau parameter (default 0.15)
	MinRate      float64 // Minimum allowed mutation probability (default 0.005)
	MaxRate      float64 // Maximum allowed mutation probability (default 0.3)
}

SelfAdaptiveController implements individual-level mutation rate adaptation.

func NewSelfAdaptiveController

func NewSelfAdaptiveController[Env any, State any](learningRate, minRate, maxRate float64) *SelfAdaptiveController[Env, State]

NewSelfAdaptiveController creates a new SelfAdaptiveController.

func (*SelfAdaptiveController[Env, State]) GetMutationScaler

func (c *SelfAdaptiveController[Env, State]) GetMutationScaler(e *Engine[Env, State]) float64

GetMutationScaler returns the baseline scale. Self-adaptation is processed per individual.

type SequenceGenome

type SequenceGenome []int

SequenceGenome represents a permutation genome.

func (SequenceGenome) Copy

func (g SequenceGenome) Copy() Genome

func (SequenceGenome) Size

func (g SequenceGenome) Size() int

type SequencingContext

type SequencingContext[Env any, State any] struct {
	BehavioralLoci      []*Locus[Env, State]
	SelectedGeneIDs     []string
	SelectedGeneIndices []int
}

SequencingContext provides information to the sequencer.

type SigmoidDiversityFeedbackController

type SigmoidDiversityFeedbackController[Env any, State any] struct {
	TargetDiversity float64 // The desired diversity level (e.g., 0.3)
	Sensitivity     float64 // Controls the steepness of the curve (e.g., 10.0)
	MinScaler       float64 // Minimum allowed scaling factor (e.g., 0.1)
	MaxScaler       float64 // Maximum allowed scaling factor (e.g., 5.0)
}

SigmoidDiversityFeedbackController implements a smooth logistic (sigmoid) feedback loop centered on a target diversity.

func NewSigmoidDiversityFeedbackController

func NewSigmoidDiversityFeedbackController[Env any, State any](target, sensitivity, minS, maxS float64) *SigmoidDiversityFeedbackController[Env, State]

NewSigmoidDiversityFeedbackController creates a new SigmoidDiversityFeedbackController.

func (*SigmoidDiversityFeedbackController[Env, State]) GetMutationScaler

func (c *SigmoidDiversityFeedbackController[Env, State]) GetMutationScaler(e *Engine[Env, State]) float64

GetMutationScaler computes the scaling factor using a sigmoid curve.

type SinglePointCrossover

type SinglePointCrossover struct{}

SinglePointCrossover performs crossover at a single random point.

func (SinglePointCrossover) Crossover

func (c SinglePointCrossover) Crossover(p1, p2 Genome) (Genome, Genome)

type StandardGeneration

type StandardGeneration[Env any, State any] struct{}

StandardGeneration implements single-objective reproduction, crossover, mutation, and elitism replacement.

func (*StandardGeneration[Env, State]) Initialize

func (s *StandardGeneration[Env, State]) Initialize(e *Engine[Env, State]) error

func (*StandardGeneration[Env, State]) NextGeneration

func (s *StandardGeneration[Env, State]) NextGeneration(e *Engine[Env, State], def *Definition[Env, State], current Population[Env, State]) (Population[Env, State], error)

type StochasticUniversalSamplingSelector

type StochasticUniversalSamplingSelector[Env any, State any] struct {
	AutoShift bool
	// contains filtered or unexported fields
}

StochasticUniversalSamplingSelector selects individuals using SUS (Stochastic Universal Sampling). Since the Selector interface selects one-by-one, this selector caches selections globally and refills the cache by performing a full SUS spin whenever the cache is fully consumed.

func (*StochasticUniversalSamplingSelector[Env, State]) Select

func (s *StochasticUniversalSamplingSelector[Env, State]) Select(pop interface{}) interface{}

Select implements the Selector interface.

func (*StochasticUniversalSamplingSelector[Env, State]) SelectTyped

func (s *StochasticUniversalSamplingSelector[Env, State]) SelectTyped(pop Population[Env, State]) *Individual[Env, State]

SelectTyped performs type-safe selection using Stochastic Universal Sampling.

type SwapMutator

type SwapMutator struct {
	Probability float64
}

SwapMutator swaps two random elements in a SequenceGenome with a given probability.

func (SwapMutator) Mutate

func (m SwapMutator) Mutate(g Genome) Genome

type TemporalScheduleController

type TemporalScheduleController[Env any, State any] struct {
	Type        MutationScheduleType
	InitialRate float64 // Initial scaling factor (typically 1.0 or higher)
	FinalRate   float64 // Minimum baseline scaling factor (e.g., 0.1)
	CycleLength int     // Generation period for Cosine Annealing (e.g., 20 generations)
}

TemporalScheduleController scales the mutation rate based on generation count.

func (*TemporalScheduleController[Env, State]) GetMutationScaler

func (c *TemporalScheduleController[Env, State]) GetMutationScaler(e *Engine[Env, State]) float64

GetMutationScaler calculates the scheduling-based scaling factor.

type TournamentSelector

type TournamentSelector struct {
	Size int
}

TournamentSelector selects the best individual from a random subset.

func (TournamentSelector) Select

func (s TournamentSelector) Select(pop interface{}) interface{}

type TwoPointCrossover

type TwoPointCrossover struct{}

TwoPointCrossover performs crossover at two random points.

func (TwoPointCrossover) Crossover

func (c TwoPointCrossover) Crossover(p1, p2 Genome) (Genome, Genome)

type UniformCrossover

type UniformCrossover struct {
	Probability float64 // typically 0.5
}

UniformCrossover swaps genes at each locus with a given probability.

func (UniformCrossover) Crossover

func (c UniformCrossover) Crossover(p1, p2 Genome) (Genome, Genome)

type WeightedCrossoverer

type WeightedCrossoverer struct {
	Crossoverer Crossoverer
	Weight      float64
}

WeightedCrossoverer pairs a crossoverer operator with its selection probability weight.

type WeightedMutator

type WeightedMutator struct {
	Mutator Mutator
	Weight  float64
}

WeightedMutator pairs a mutator operator with its selection probability weight.

Directories

Path Synopsis
examples
advanced command
comprehensive command
islands command
multiobjective command
onemax command
structured command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL