A high-performance agent-based model for studying sexual selection and cultural-genetic coevolution. Built with Mesa-Frames and Polars for vectorized operations on large populations (10k+ individuals).
LoveBug is a research-oriented computational laboratory for investigating the evolution of mate choice through multiple inheritance mechanisms. The model integrates genetic inheritance, social learning, perceptual constraints, and cultural transmission within a unified framework designed to test theoretical predictions and replicate empirical findings from evolutionary biology literature.
The model addresses fundamental questions in sexual selection and cultural evolution:
- When do genetic vs. cultural mechanisms dominate mate choice evolution?
- How do social learning and cultural transmission interact with genetic inheritance?
- What role do perceptual constraints play in trait-preference coevolution?
- Can cultural transmission functionally substitute for genetic linkage in sexual selection?
- Vectorized core: All agents stored in Polars DataFrames; handles 100k+ individuals efficiently
- Unlinked gene architecture: 32-bit genome encoding display traits, mate preferences, and behavioral thresholds
- Mesa-Frames compatibility: Full integration with Mesa's agent-based modeling framework
- Two-layer evolution: Genetic inheritance (Layer 1) + cultural learning (Layer 2)
- Multiple learning strategies: Mate-choice copying, conformist bias, prestige bias
- Perceptual realism: Noisy sensory channels and detection thresholds
- Network effects: Configurable social network topologies for cultural transmission
- Literature replications: Quantitative reproduction of landmark empirical studies
- Theory validation: Recovers Fisher-Lande-Kirkpatrick dynamics without genetic linkage
- Parameter exploration: Latin Hypercube Sampling across genetic-cultural parameter space
git clone https://github.com/adamamer20/lovebug.git
cd lovebug
uv sync --all-extras
from lovebug import LoveModel, LoveBugConfig, GeneticParams, CulturalParams, LayerConfig, SimulationParams
# Genetic-only evolution
config = LoveBugConfig(
name="genetic_only_simulation",
genetic=GeneticParams(
mutation_rate=0.01,
crossover_rate=0.7,
h2_trait=0.8,
h2_preference=0.8,
),
cultural=CulturalParams(),
simulation=SimulationParams(population_size=5000),
layer=LayerConfig(genetic_enabled=True, cultural_enabled=False)
)
model = LoveModel(config=config)
model.run_model()
print(f"Final population: {len(model.agents)}")
# Complete experimental pipeline
uv run python experiments/paper_experiments.py --run-empirical --run-lhs
# Quick validation test
uv run python experiments/paper_experiments.py --quick-test
# Literature replications only
uv run python experiments/paper_experiments.py --run-empirical
# Parameter space exploration
uv run python experiments/paper_experiments.py --run-lhs --lhs-samples 100
flowchart TD
A[Population Initialization] --> B[Agent Lifecycle]
B --> C{Step Execution}
C --> D[1 - Ecology Phase]
C --> E[2 - Cultural Phase]
C --> F[3- Mating Phase]
D --> D1[Energy Acquisition]
D --> D2[Metabolism & Aging]
D --> D3[Survival Filtering]
E --> E1[Cultural Innovation]
E --> E2[Social Learning]
E --> E3[Network Effects]
F --> F1[Preference Blending]
F --> F2[Courtship Assessment]
F --> F3[Mutual Acceptance]
F --> F4[Genetic Recombination]
D3 --> G[Population Update]
E3 --> G
F4 --> G
G --> H{Continue?}
H -->|Yes| C
H -->|No| I[Results Collection]
graph LR
A[Agent] --> B[Genetic Traits]
A --> C[Cultural Traits]
A --> D[State Variables]
B --> B1[gene_display: UInt16]
B --> B2[gene_preference: UInt16]
B --> B3[gene_threshold: UInt8]
B --> B4[gene_foraging_efficiency: UInt8]
C --> C1[cultural_preference: UInt16]
C --> C2[social_network_neighbors: List]
C --> C3[effective_preference: UInt16]
D --> D1[energy: Float32]
D --> D2[age: UInt16]
D --> D3[sex: UInt8]
D --> D4[mating_success: UInt16]
The model implements an unlinked multi-gene architecture where agents possess separate, independently assorting genetic loci:
Component | Type | Bits | Description |
---|---|---|---|
Display Trait | gene_display |
16-bit UInt16 | Ornamental features visible to potential mates |
Mate Preference | gene_preference |
16-bit UInt16 | Innate attraction pattern for mate assessment |
Choosiness Threshold | gene_threshold |
4-bit UInt8 | Behavioral selectivity in mate acceptance |
Foraging Efficiency | gene_foraging_efficiency |
8-bit UInt8 | Survival-related foraging capability |
Cultural Preference | cultural_preference |
16-bit UInt16 | Learned mate preference from social observation |
Effective Preference | effective_preference |
16-bit UInt16 | Blended genetic-cultural preference (combined models) |
# Density-dependent energy acquisition
density_factor = max(0.1, 1.0 - (current_pop / carrying_capacity) ** 2)
energy_gain = base_energy * density_factor * foraging_efficiency
# Display-survival trade-off
display_cost = display_bits.count() / 16.0 * display_cost_scalar
effective_foraging = (foraging_efficiency - display_cost).clip(0.1, 1.0)
# Survival filtering
survivors = agents.filter((age < max_age) & (energy > 0))
# Cultural innovation
if random() < innovation_rate:
cultural_preference = random_16bit_pattern()
# Social learning strategies
if learning_strategy == "conformist":
new_preference = mode(neighbor_preferences)
elif learning_strategy == "success-biased":
new_preference = preference_of_most_successful_neighbor()
# Preference blending (combined models)
effective_preference = (genetic_weight * gene_preference +
cultural_weight * cultural_preference)
# Hamming similarity-based mate assessment
similarity = 16 - bitcount(display_partner ⊕ effective_preference_self)
acceptance_prob = sigmoid(steepness * (similarity - threshold))
# Genetic recombination (unlinked inheritance)
offspring_display = random_choice(parent_a_display, parent_b_display)
offspring_preference = random_choice(parent_a_preference, parent_b_preference)
The model supports four evolutionary regimes through LayerConfig
:
Mode | Genetic Enabled | Cultural Enabled | Description |
---|---|---|---|
Genetic-only | ✓ | ✗ | Pure Fisher-Lande-Kirkpatrick dynamics |
Cultural-only | ✗ | ✓ | Social learning without genetic evolution |
Combined | ✓ | ✓ | Synergistic genetic-cultural coevolution |
Validation | ✓ | ✗ | Testing/comparison baseline |
- Polars DataFrames: All agent data stored in columnar format for vectorized operations
- Hamming similarity: Native Rust-optimized
bitwise_count_ones()
function - Batch mutations: Vectorized bit-flipping across entire population
- Network operations: Fully vectorized social network neighbor retrieval
- Bit-packed genomes: Multiple traits encoded in single integers
- Lazy evaluation: Polars expressions evaluated only when needed
- Zero-copy operations: In-place DataFrame modifications where possible
- Carrying capacity: Density-dependent resource competition
- Energy system: Metabolic costs, foraging efficiency, parental investment
- Age structure: Natural mortality and maximum lifespan limits
- Juvenile costs: Start-up energy requirements for offspring survival
- Sensory noise: Gaussian noise in mate assessment (
sigma_perception
) - Detection thresholds: Minimum similarity for mate recognition (
theta_detect
) - Sigmoid acceptance: Probabilistic mate choice with configurable steepness
- Network topologies: Small-world, scale-free, random network structures
- Learning strategies: Conformist, success-biased, condition-dependent, age-biased
- Cultural innovation: Spontaneous generation of novel preferences
- Memory dynamics: Cultural preference updating and decay
Validates model against established empirical findings:
- Dugatkin (1992): Mate-choice copying in guppies
- Witte et al. (2002): Cultural transmission of mate preferences
- Rodd et al. (2002): Sensory bias driven trait evolution
Systematic exploration using Latin Hypercube Sampling:
- Genetic-only regime: Pure Fisher-Lande-Kirkpatrick dynamics
- Cultural-only regime: Social learning without genetic evolution
- Combined regime: Synergistic genetic-cultural coevolution
Tests three classic sexual selection scenarios:
- Stasis: Moderate heritability, balanced energy → no trait-preference correlation
- Runaway: High heritability, abundant energy → trait elaboration
- Costly Choice: High heritability, scarce energy → constrained evolution
- Synergistic acceleration: Combined genetic-cultural evolution is 2.3x faster than purely genetic systems
- Functional substitution: Cultural transmission can replace genetic linkage in driving trait-preference coevolution
- Regime identification: Clear parameter boundaries between genetic-dominant, cultural-dominant, and synergistic regimes
- Population stability: Mixed inheritance systems show greater demographic robustness than pure mechanisms
- Population size: 1,500 agents (optimal for ~11h full experimental suite)
- Generations: 3,000 steps for equilibrium dynamics
- Replications: 10 per condition for statistical robustness
- LHS samples: 100 per parameter sweep
# Single job optimization
export POLARS_MAX_THREADS=20 RAYON_NUM_THREADS=20
# Dual concurrent jobs
export POLARS_MAX_THREADS=10 RAYON_NUM_THREADS=10
- Vectorized operations: All agent updates use Polars expressions
- Bit-packed genomes: 32-bit integers store multiple traits efficiently
- Lazy evaluation: Memory-efficient data processing pipelines
- Research Paper - Complete scientific methodology and findings
((Coming Soon)
# Install dependencies
uv sync --all-extras
# Run tests
uv run pytest
# Code quality
uv run ruff check .
uv run ruff format .
# Documentation
make docs
We welcome contributions from researchers and developers!
- Fork the repository and create a feature branch
- Follow code standards: Use
ruff
for formatting and linting - Add tests: Ensure new features have appropriate test coverage
- Update documentation: Include docstrings and update relevant guides
- Submit pull request: With clear description of changes and rationale
- Type hints: Use beartype decorators for runtime type checking
- Documentation: Comprehensive docstrings following NumPy style
- Testing: pytest with parametrized tests for robustness
- Performance: Profile code changes affecting simulation speed
MIT © 2025 Adam Amer. See LICENSE for full terms.
If you use LoveBug in academic work, please cite:
@misc{lovebug2025,
title = {LoveBug: An agent-based model for studying sexual selection and cultural-genetic coevolution},
author = {Adam Amer},
year = {2025},
journal = {In preparation},
howpublished = {GitHub repository},
url = {https://github.com/adamamer20/lovebug}
}
- Documentation - Complete documentation site
- GitHub Repository - Source code and development
- Issue Tracker - Bug reports and feature requests
For research collaboration or technical support, please open an issue on GitHub or contact the development team.
Happy evolutionary modeling! 🐞🧬✨