OpenEvolve: An Open Source Implementation of Google DeepMind's AlphaEvolve

Community Article Published May 20, 2025

Harnessing LLMs for Evolutionary Algorithm Discovery

OpenEvolve Logo

Introduction

Google DeepMind recently announced AlphaEvolve, an evolutionary coding agent that uses Large Language Models to optimize code through an iterative process. This system has been used to make breakthroughs in mathematical algorithms and optimize critical computing infrastructure.

Today, I'm excited to introduce OpenEvolve, an open-source implementation of the AlphaEvolve system that brings these capabilities to the broader research and development community. This article will walk through the architecture of OpenEvolve, showcase two successful examples where we've replicated AlphaEvolve's results, and provide insights on how you can use it for your own projects.

Background: Evolutionary Coding Agents

The idea of evolving code isn't new - genetic programming has been around for decades. However, the combination of modern LLMs with evolutionary techniques creates a powerful new paradigm.

AlphaEvolve represents a significant advancement in this field by:

  1. Using LLMs to generate sophisticated code modifications
  2. Evaluating these modifications with automated metrics
  3. Using an evolutionary framework to improve promising solutions
  4. Evolving entire codebases, not just individual functions

OpenEvolve implements these principles in a flexible, configurable open-source package.

Technical Architecture

OpenEvolve follows an evolutionary approach with four key components:

OpenEvolve Architecture

  1. Prompt Sampler: Creates context-rich prompts containing past programs, their scores, and problem descriptions
  2. LLM Ensemble: Generates code modifications via an ensemble of language models
  3. Evaluator Pool: Tests generated programs and assigns scores
  4. Program Database: Stores programs and their evaluation metrics, guiding future evolution

The controller orchestrates interactions between these components in an asynchronous pipeline, maximizing throughput to evaluate as many candidate solutions as possible.

Key Features

  • Evolution of entire code files (not just single functions)
  • Support for multiple programming languages
  • Multi-objective optimization
  • Flexible prompt engineering
  • Distributed evaluation
  • LLM ensemble approach
  • Checkpoint system for resuming runs

Example 1: Circle Packing

One of the problems tackled in the AlphaEvolve paper was packing 26 circles of varying sizes into a unit square to maximize the sum of their radii. Google reported achieving a sum of 2.635.

We replicated this experiment using OpenEvolve, targeting the same objective. Our implementation evolved through multiple stages:

Initial Solution

# Initial attempt
# Place a large circle in the center
centers[0] = [0.5, 0.5]

# Place 8 circles around it in a ring
for i in range(8):
    angle = 2 * np.pi * i / 8
    centers[i + 1] = [0.5 + 0.3 * np.cos(angle), 0.5 + 0.3 * np.sin(angle)]

# Place 16 more circles in an outer ring
for i in range(16):
    angle = 2 * np.pi * i / 16
    centers[i + 9] = [0.5 + 0.7 * np.cos(angle), 0.5 + 0.7 * np.sin(angle)]

This simple approach produced a sum of approximately 1.87.

Evolution to Generation 10

By generation 10, OpenEvolve had discovered a more sophisticated hexagonal arrangement:

# Generation 10
# Parameters for the arrangement (fine-tuned)
r_center = 0.1675  # Central circle radius

# 1. Place central circle
centers[0] = [0.5, 0.5]
radii[0] = r_center

# 2. First ring: 6 circles in hexagonal arrangement
r_ring1 = 0.1035
ring1_distance = r_center + r_ring1 + 0.0005  # Small gap for stability
for i in range(6):
    angle = 2 * np.pi * i / 6
    centers[i+1] = [
        0.5 + ring1_distance * np.cos(angle),
        0.5 + ring1_distance * np.sin(angle)
    ]
    radii[i+1] = r_ring1

This improved the sum to approximately 2.18.

Generation 100: Grid-Based Approach

By generation 100, OpenEvolve had pivoted to a grid-based strategy:

# Generation 100
# Row 1: 5 circles
centers[0] = [0.166, 0.166]
centers[1] = [0.333, 0.166]
centers[2] = [0.500, 0.166]
centers[3] = [0.667, 0.166]
centers[4] = [0.834, 0.166]

# Row 2: 6 circles (staggered)
centers[5] = [0.100, 0.333]
centers[6] = [0.266, 0.333]
# ... additional circles

This grid pattern achieved a sum of approximately 2.32.

Final Solution: Mathematical Optimization

The breakthrough came when OpenEvolve discovered the power of mathematical optimization:

# Final solution with scipy.optimize
def construct_packing():
    # ... initialization code ...
    
    # Objective function: Negative sum of radii (to maximize)
    def objective(x):
        centers = x[:2*n].reshape(n, 2)
        radii = x[2*n:]
        return -np.sum(radii)

    # Constraint: No overlaps and circles stay within the unit square
    def constraint(x):
        centers = x[:2*n].reshape(n, 2)
        radii = x[2*n:]
        
        # Overlap constraint
        overlap_constraints = []
        for i in range(n):
            for j in range(i + 1, n):
                dist = np.sqrt(np.sum((centers[i] - centers[j])**2))
                overlap_constraints.append(dist - (radii[i] + radii[j]))
        # ... boundary constraints ...
        
    # Optimization using SLSQP
    result = minimize(objective, x0, method='SLSQP', bounds=bounds, 
                      constraints=constraints)

This approach achieved a sum of 2.634, matching the AlphaEvolve paper's result of 2.635 to within 0.04%!

Circle Packing Evolution

Final packing arrangement with a sum of radii = 2.634

Two-Phase Approach

We structured the evolution in two phases:

Phase 1: Initial Exploration

  • Focus on different fundamental approaches
  • Constructor-based pattern exploration
  • Population size: 60
  • Islands: 4
  • Exploitation ratio: 0.7

Phase 2: Breaking Through the Plateau

  • Focus on radical innovation
  • Increased population size to 70
  • Islands: 5
  • Reduced exploitation ratio to 0.6
  • Updated system prompt to suggest optimization techniques

This two-phase strategy proved crucial for breaking through plateaus in the solution space.

Example 2: Function Minimization

Our second example focused on minimizing a complex non-convex function:

f(x, y) = sin(x) * cos(y) + sin(x*y) + (x^2 + y^2)/20

The global minimum is approximately at (-1.704, 0.678) with a value of -1.519.

Initial Algorithm: Random Search

We started with a simple random search:

def search_algorithm(iterations=1000, bounds=(-5, 5)):
    # Initialize with a random point
    best_x = np.random.uniform(bounds[0], bounds[1])
    best_y = np.random.uniform(bounds[0], bounds[1])
    best_value = evaluate_function(best_x, best_y)
    
    for _ in range(iterations):
        # Simple random search
        x = np.random.uniform(bounds[0], bounds[1])
        y = np.random.uniform(bounds[0], bounds[1])
        value = evaluate_function(x, y)
        
        if value < best_value:
            best_value = value
            best_x, best_y = x, y
    
    return best_x, best_y, best_value

Evolved Algorithm: Simulated Annealing

Through evolution, OpenEvolve discovered a simulated annealing algorithm:

def simulated_annealing(bounds=(-5, 5), iterations=1000, step_size=0.1, 
                       initial_temperature=100, cooling_rate=0.99):
    # Initialize with a random point
    best_x = np.random.uniform(bounds[0], bounds[1])
    best_y = np.random.uniform(bounds[0], bounds[1])
    best_value = evaluate_function(best_x, best_y)

    current_x, current_y = best_x, best_y
    current_value = best_value
    temperature = initial_temperature

    for _ in range(iterations):
        # Perturb the current solution
        new_x = current_x + np.random.uniform(-step_size, step_size)
        new_y = current_y + np.random.uniform(-step_size, step_size)

        # Ensure the new solution is within bounds
        new_x = max(bounds[0], min(new_x, bounds[1]))
        new_y = max(bounds[0], min(new_y, bounds[1]))

        new_value = evaluate_function(new_x, new_y)

        # Calculate the acceptance probability
        if new_value < current_value:
            current_x, current_y = new_x, new_y
            current_value = new_value

            if new_value < best_value:
                best_x, best_y = new_x, new_y
                best_value = new_value
        else:
            probability = np.exp((current_value - new_value) / temperature)
            if np.random.rand() < probability:
                current_x, current_y = new_x, new_y
                current_value = new_value

        # Cool down the temperature
        temperature *= cooling_rate

    return best_x, best_y, best_value

The evolved algorithm discovered key optimization concepts:

  1. Local search with small perturbations
  2. Temperature-based acceptance to escape local minima
  3. Cooling schedule for exploration-exploitation balance
  4. Parameter tuning for optimal performance

LLM Performance Analysis

A critical factor in OpenEvolve's success is the LLM ensemble. We found:

  1. Low latency is essential - We need many generations, so fast inference is crucial
  2. Model diversity helps - Different models have different strengths
  3. Best combination: Gemini-Flash-2.0-lite + Gemini-Flash-2.0 for most tasks
  4. Cerebras AI's API provided the fastest inference speeds
  5. For circle packing: Gemini-Flash-2.0 + Claude-Sonnet-3.7 worked best

The key insight: for evolutionary code optimization, you need a balance of speed and quality. Using a faster model for most generations with occasional calls to a more powerful model provides the best results.

How to Use OpenEvolve

Getting started with OpenEvolve is straightforward:

Installation

git clone https://github.com/codelion/openevolve.git
cd openevolve
pip install -e .

Using the Python API

from openevolve import OpenEvolve

# Initialize the system
evolve = OpenEvolve(
    initial_program_path="path/to/initial_program.py",
    evaluation_file="path/to/evaluator.py",
    config_path="path/to/config.yaml"
)

# Run the evolution
best_program = await evolve.run(iterations=1000)
print(f"Best program metrics:")
for name, value in best_program.metrics.items():
    print(f"  {name}: {value:.4f}")

Using the Command Line

python openevolve-run.py path/to/initial_program.py path/to/evaluator.py \
  --config path/to/config.yaml --iterations 1000

Key Configuration Parameters

# Example configuration
max_iterations: 1000
llm:
  primary_model: "gemini-2.0-flash-lite"
  secondary_model: "gemini-2.0-flash" 
  temperature: 0.7
database:
  population_size: 500
  num_islands: 5
  exploitation_ratio: 0.7

Preparing Your Own Problems

  1. Mark code sections to evolve with # EVOLVE-BLOCK-START and # EVOLVE-BLOCK-END comments
  2. Create an evaluation function that returns a dictionary of metrics
  3. Configure OpenEvolve with appropriate parameters
  4. Run the evolution process

Future Directions

While OpenEvolve already demonstrates impressive capabilities, there are several exciting directions for future development:

  1. Supporting more LLM providers through standardized interfaces
  2. Improved prompt engineering with automatic adaptation
  3. More sophisticated evaluation cascades for faster pruning of poor solutions
  4. GUI-based monitoring and control of the evolution process
  5. Expanded example library covering more domains

Conclusion

OpenEvolve brings the power of evolutionary algorithm discovery to the open-source community. By combining LLMs with automated evaluation in an evolutionary framework, it enables the discovery of novel algorithms across domains.

Our replication of AlphaEvolve's circle packing and function minimization examples demonstrates the system's effectiveness. The ability to transform simple implementations into sophisticated algorithms - like evolving from concentric rings to mathematical optimization, or from random search to simulated annealing - showcases the power of guided evolutionary search.

We invite you to try OpenEvolve, contribute to its development, and apply it to your own algorithmic challenges. The code is available on GitHub at https://github.com/codelion/openevolve.

Resources


If you enjoyed this article, please consider starring the repository and contributing to the project!

Community

Sign up or log in to comment