This example demonstrates using ShinkaEvolve for Architecture, Engineering, and Construction (AEC) applications, specifically optimizing toilet layout packing in bathrooms to minimize space while satisfying design constraints.
The goal is to find an optimal toilet layout that minimizes the total perimeter (and thus required space) while satisfying hard constraints related to accessibility, fixture placement, and corridor design.
Element Types:
- WC (Water Closet): Toilet fixtures
- Urinal: Urinal fixtures
- Wash Basin: Sink fixtures
- Corridor: Passage areas for accessibility
Representation:
- Blue (B): Fixture outlines
- Red (R): Corridor/passage areas
- Index: Variations within the same type (e.g., WC-1, WC-2 with different door positions)
- No B/B Overlap: Blue fixtures cannot overlap with each other
- No B/R Overlap: Blue fixtures cannot overlap with red corridors
- Type Adjacency: Fixtures of the same type must be placed adjacent to each other
- Accessibility: Corridors (R) cannot be completely enclosed by fixtures (B) - all fixtures must be accessible
- Perimeter Boundary: Green line must border the perimeter
- Minimize Total Perimeter: Minimize sum of perimeters of all WC, Urinal, and Wash Basin elements
- R/R Overlap Preference: Corridors should preferably overlap to consolidate passage space
- Minimize Corridor Count: Use fewer corridors for area reduction
aec_packing/
├── README.md # This file
├── initial.py # Initial packing solution (starting point)
├── evaluate.py # Evaluation and validation logic
├── run_evo.py # Evolution configuration and runner
└── results_cpack/ # Results directory (created during run)
├── evolution_db.sqlite # Evolution database
├── logs/ # Execution logs
└── programs/ # Generated program variants
# Navigate to ShinkaEvolve root directory
cd ShinkaEvolve
# Create virtual environment (using uv - recommended)
uv venv --python 3.11
source .venv/bin/activate # On macOS/Linux
# .venv\Scripts\activate # On Windows
# Install ShinkaEvolve
uv pip install -e .Create a .env file in the ShinkaEvolve root directory:
# .env file
OPENAI_API_KEY=sk-proj-your-key-here # For OpenAI models (text-embedding-3-small, gpt-4o, etc.)
GEMINI_API_KEY=your-gemini-key-here # For Gemini models (gemini-2.5-flash, gemini-2.5-pro, etc.)
ANTHROPIC_API_KEY=your-anthropic-key-here # For Anthropic models (claude-sonnet, etc.)Important: You only need to provide the API key(s) for the model(s) you plan to use. By default, this example uses:
gemini-2.5-flashfor LLM operations (requiresGEMINI_API_KEY)text-embedding-3-smallfor embeddings (requiresOPENAI_API_KEY)
If you only have one provider's API key, edit run_evo.py to use models from that provider for both LLM and embedding operations. For example:
- Gemini only: Use
gemini-2.5-flashfor LLM andgemini-embedding-001for embeddings - OpenAI only: Use
gpt-4ofor LLM andtext-embedding-3-smallfor embeddings
💡 Pro Tip - Model Selection Strategy: Smaller, faster models (like gemini-2.5-flash) tend to be quick but less sophisticated, while larger models (like gemini-2.5-pro or gpt-4o) are slower but produce higher-quality solutions. ShinkaEvolve's strength is that you can use both strategically:
- Early generations (Exploration): Use smaller/faster models to rapidly explore the solution space and generate diverse candidates
- Later generations (Exploitation): Switch to larger/smarter models to refine and optimize the best solutions
You can configure this in run_evo.py by adjusting llm_models list or implementing custom logic to change models based on generation number.
cd examples/aec_packingpython evaluate.py --program_path initial.py --results_dir test_resultsThis will evaluate the initial circle packing solution to ensure everything is set up correctly.
python run_evo.pyThis will:
- Initialize the evolution with the program in
initial.py - Run for 400 generations (configurable in
run_evo.py) - Use 2 evolutionary islands with population migration
- Maintain an archive of top 40 solutions
- Save results to
results_cpack/
The evolution will print progress to the console:
Generation 0: Best score: 2.345
Generation 1: Best score: 2.567
...
Results are continuously saved to:
results_cpack/evolution_db.sqlite- Database with all evolved programsresults_cpack/logs/- Detailed logsresults_cpack/programs/- Generated program files
Edit run_evo.py to customize the evolution:
Choose from multiple parent selection strategies:
strategy = "weighted" # Options: uniform, hill_climbing, weighted, power_law, beam_searchevo_config = EvolutionConfig(
num_generations=400, # Number of evolution iterations
max_parallel_jobs=5, # Parallel evaluation workers
patch_types=["diff", "full", "cross"], # Mutation types
patch_type_probs=[0.6, 0.3, 0.1], # Probability distribution
...
)db_config = DatabaseConfig(
num_islands=2, # Number of evolutionary islands
archive_size=40, # Size of elite archive
migration_interval=10, # Generations between migrations
migration_rate=0.1, # Probability of migration
...
)llm_models=[
"gemini-2.5-flash", # Primary model (fast and cheap)
# "gemini-2.5-pro", # More capable (slower, more expensive)
# "gpt-4o", # OpenAI alternative
],
llm_kwargs=dict(
temperatures=[0.0, 0.5, 1.0], # Diversity control
reasoning_efforts=["auto", "low", "medium", "high"], # For reasoning models
max_tokens=32768,
),For code similarity detection:
embedding_model="text-embedding-3-small", # OpenAI (recommended)
# embedding_model="gemini-embedding-001", # Gemini alternativeContains the initial circle packing implementation with:
construct_packing(): Creates the initial layout of 26 circlescompute_max_radii(): Calculates maximum valid radii without overlapsrun_packing(): Entry point called by the evaluator
Evolution Target: Only the code between # EVOLVE-BLOCK-START and # EVOLVE-BLOCK-END is evolved.
Defines how solutions are validated and scored:
adapted_validate_packing(): Checks constraints (no overlaps, within bounds)aggregate_circle_packing_metrics(): Computes final score (sum of radii)main(): Entry point for evaluation
Configures and launches the evolution:
- System message defining the task
- Evolution parameters (generations, population, mutations)
- Database configuration (islands, archives)
- LLM models and parameters
The evolution process should:
- Start with the initial solution from
initial.py - Generate variations using LLM-powered mutations
- Evaluate each variant using
evaluate.py - Select successful variants for further evolution
- Progressively improve the sum of radii over generations
Best Solution: Saved in results_cpack/evolution_db.sqlite and accessible via the database
To visualize results, you can use the Shinka visualization tools:
# From ShinkaEvolve root directory
python -m shinka.plots.plot_improvement results_cpack/evolution_db.sqlite
python -m shinka.plots.plot_lineage_tree results_cpack/evolution_db.sqliteOr explore using the Web UI (see docs/webui.md).
Error: OPENAI_API_KEY not found
Solution: Ensure .env file is in the ShinkaEvolve root directory with valid API keys.
ValueError: Invalid embedding model: gemini-embedding-exp-03-07
Solution: The experimental model expired. Change to stable model in run_evo.py:
embedding_model="text-embedding-3-small", # Use this insteadIf you encounter memory issues with large populations:
- Reduce
num_islands(e.g., from 2 to 1) - Reduce
archive_size(e.g., from 40 to 20) - Reduce
max_parallel_jobs(e.g., from 5 to 2)
To speed up evolution:
- Use faster models:
gemini-2.5-flashinstead ofgemini-2.5-pro - Reduce temperature variety:
temperatures=[0.5] - Increase
max_parallel_jobsif you have spare CPU cores
Edit evaluate.py to add custom metrics in aggregate_circle_packing_metrics():
public_metrics = {
"centers_str": format_centers_string(centers),
"num_circles": centers.shape[0],
"custom_metric": your_calculation_here,
}Modify the combined_score calculation to balance multiple objectives:
combined_score = alpha * sum_radii - beta * total_perimeterAdjust tolerance in validation:
atol = 1e-6 # Increase for looser constraints- ShinkaEvolve Documentation: See
docs/directory in root - Configuration Guide:
docs/configuration.md - Getting Started:
docs/getting_started.md - Circle Packing Example:
examples/circle_packing/(similar problem)
If you use this example in your research, please cite the ShinkaEvolve framework:
@software{shinka2024,
title={ShinkaEvolve: LLM-Driven Evolutionary Algorithms for Scientific Discovery},
author={[Author names]},
year={2024},
url={[Repository URL]}
}This example is part of the ShinkaEvolve project. See LICENSE file in the root directory.