Seedler
Seedler is a high-performance Python package powered by Rust, designed for large-scale Monte Carlo simulations and RNG seed discovery. By leveraging Rust's speed and safety alongside Python's flexibility, Seedler allows you to simulate millions of scenarios, filter results with complex logic, and perfectly recreate specific outcomes using deterministic seeding.
Key Features
- Fast Core: Simulation loops and RNG generation are handled in Rust.
- Deterministic Re-simulation: Every result is tied to a u64 seed, allowing 100% reproducible results.
- Flexible Callbacks: Use Python classes to define your "Planter" (simulation logic) and "Fire" (filtering logic).
- Memory Efficient: Designed to handle millions of iterations without ballooning memory usage.
Installation
Pip
UV
System Requirements
Seedler includes a Rust extension that must be compiled during installation. You must install Rust before installing this package.
Windows Users
- Install Rust
Download and install Rust:
-
Install Visual C++ Build Tools
Download and run:
During installation: - Select "Desktop development with C++" - Click Install
macOS Users
- Install Rust
Install Rust:
Troubleshooting
If installation fails with errors like:
can't find Rust compiler Microsoft Visual C++ 14.0 is required
It usually means one of the required tools is not installed correctly.
Development
From Source. Seedler requires the Rust toolchain and maturin to build the native extension.
git clone git+https://github.com/byuirpytooling/seedler.git@main
cd seedler-repo
uv venv --python 3.14
source .venv/bin/activate
uv pip install -e .
uv run maturin develop
Quick Start
Seedler uses Garden and Planting metaphors for simulations:
- Sprout: The container for a single simulation run (holds the RNG and results).
- Planter: Defines the logic of what happens during the simulation.
- Fire: Defines the conditions that "purge" (filter out) a simulation.
Simple 3-Card Monte Example
Find which seeds result in a "Win" (selecting the passing card) out of 100 simulations.
from seedler import Planter, Sprout, Fire
# Flags
WIN = 0
LOSE = 1
# 1. Define your Simulation Logic
class CardMontePlanter(Planter):
def plant(self, sprout: Sprout):
# 0 is Win, 1 & 2 are Lose
cards = [WIN, LOSE, LOSE]
# Use Rust-backed RNG via sprout.growth(min, max)
outcome = cards[sprout.growth(0, 2)]
sprout.add_bud(outcome)
# 2. Define your Filtering Logic
class PurgeLosses(Fire):
def purge(self, sprout: Sprout):
# If we didn't get a 'WIN', burn the seed
return sprout.get_bud_count(WIN) == 0
# 3. Run the Lab
lab = CardMontePlanter()
winning_seeds = lab.find_seeds(
fire=PurgeLosses(),
minimum=0,
maximum=100
)
print(f"Found {len(winning_seeds)} winning seeds.")
Re-Simulating Single Seeds
One of Seedler's strengths is the ability to recreate a complex simulation state instantly using only its seed.
# Assuming you have a seed from a previous run
seed = [EXAMPLE SEED]
sprout = Sprout(seed)
lab.plant(sprout)
print(f"Results for seed {seed}: {sprout.to_dict()}")
Data Analysis with Pandas
Seedler integrates seamlessly with Pandas for post-simulation analysis. The get_data() method returns a structured format that can be converted into a DataFrame instantly.
import pandas as pd
from seedler import Planter
lab = MyCustomPlanter()
results = lab.find_seeds(minimum=0, maximum=1000)
# Convert Planter results to a DataFrame
# get_data() returns List[Tuple[int, Dict]]
df = pd.DataFrame([
{"seed": seed, **data}
for seed, data in results
])
# Perform standard analysis
print(df.describe())
print(df['my_stat'].mean())
Benchmarking
Seedler is optimized for "Seed Hunting"—searching for specific RNG outcomes across massive ranges. Because the loop and RNG state reside in Rust, Seedler significantly outperforms pure Python implementations by minimizing the overhead of the Python interpreter for the core simulation logic.
| Iterations | Pure Python (s) | Seedler (s) | Speedup |
|---|---|---|---|
| 100,000 | 0.58 | 0.06 | 9.00x |
| 1,000,000 | 5.68 | 0.67 | 8.51x |
| 5,000,000 | 28.51 | 3.35 | 8.50x |
| 10,000,000 | 58.07 | 7.20 | 8.07x |
Note: Benchmarks performed on Apple M3 Pro, 8GB RAM. Actual performance gains scale with the number of iterations and the efficiency of your Python-side
plantandpurgecallbacks.
Contributing
Contributions are welcome! Please ensure that any Rust changes include updated tests and satisfy cargo fmt.
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
License
Distributed under the MIT License. See LICENSE for more information.
Authors:
- Dallin Wolfer - wol23003@byui.edu
- Alyssa Cox - cox24018@byui.edu
Project Link: https://github.com/byuirpytooling/seedler