Skip to content

Commit 8ca20f7

Browse files
author
Akshat Gupta
committed
Added generated data
1 parent 62263b1 commit 8ca20f7

16,432 files changed

Lines changed: 578624 additions & 5 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

examples/circle_packing2/README.md

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
# Circle Packing Example
2+
3+
This example demonstrates how OpenEvolve can be used to tackle the challenging mathematical problem of circle packing, a classic problem in computational geometry. Specifically, we focus on packing 26 circles of varying sizes into a unit square to maximize the sum of their radii, replicating one of the tasks from the AlphaEvolve paper.
4+
5+
## Problem Overview
6+
7+
The circle packing problem involves placing n non-overlapping circles inside a container (in this case, a unit square) to optimize a specific metric. For this example:
8+
9+
- We pack exactly 26 circles
10+
- Each circle must lie entirely within the unit square
11+
- No circles may overlap
12+
- We aim to maximize the sum of all circle radii
13+
14+
According to the AlphaEvolve paper, a solution with a sum of radii of approximately 2.635 is achievable for n=26. Our goal was to match or exceed this result.
15+
16+
## Our Approach
17+
18+
We structured our evolution in two phases, each with a different configuration to encourage exploration and exploitation at different stages:
19+
20+
### Phase 1: Initial Exploration
21+
22+
In the first phase, we focused on exploring different fundamental approaches to the packing problem:
23+
24+
- Used a constructor-based approach that places circles in strategic positions
25+
- Explored various geometric patterns (concentric rings, grid-based arrangements, etc.)
26+
- Developed simple optimization routines to maximize circle sizes without overlaps
27+
28+
Configuration highlights:
29+
```yaml
30+
max_iterations: 100
31+
population_size: 60
32+
num_islands: 4
33+
exploitation_ratio: 0.7
34+
```
35+
36+
### Phase 2: Breaking Through the Plateau
37+
38+
After the initial exploration phase, we observed our solutions plateauing around 2.377. For the second phase, we reconfigured OpenEvolve to encourage more radical innovations:
39+
40+
- Increased the population size to promote diversity
41+
- Lowered the exploitation ratio to favor exploration
42+
- Updated the system prompt to suggest different optimization techniques
43+
- Allowed for longer and more complex code solutions
44+
45+
Configuration highlights:
46+
```yaml
47+
max_iterations: 100
48+
population_size: 70
49+
num_islands: 5
50+
exploitation_ratio: 0.6
51+
```
52+
53+
## Evolution Progress
54+
55+
We tracked the evolution over 470 generations, capturing visualizations at each checkpoint. The progression shows dramatic improvements in the packing strategy:
56+
57+
### Initial Solution (Generation 0)
58+
59+
The initial program used a simple constructive approach with a central circle and two concentric rings:
60+
61+
```python
62+
# Initial attempt
63+
# Place a large circle in the center
64+
centers[0] = [0.5, 0.5]
65+
66+
# Place 8 circles around it in a ring
67+
for i in range(8):
68+
angle = 2 * np.pi * i / 8
69+
centers[i + 1] = [0.5 + 0.3 * np.cos(angle), 0.5 + 0.3 * np.sin(angle)]
70+
71+
# Place 16 more circles in an outer ring
72+
for i in range(16):
73+
angle = 2 * np.pi * i / 16
74+
centers[i + 9] = [0.5 + 0.7 * np.cos(angle), 0.5 + 0.7 * np.sin(angle)]
75+
```
76+
77+
This approach yielded a sum of radii of approximately 0.959.
78+
79+
![Initial Circle Packing](circle_packing_1.png)
80+
81+
### Generation 10 Breakthrough
82+
83+
By generation 10, OpenEvolve had already discovered a more sophisticated approach:
84+
85+
```python
86+
# Generation 10
87+
# Parameters for the arrangement (fine-tuned)
88+
r_center = 0.1675 # Central circle radius
89+
90+
# 1. Place central circle
91+
centers[0] = [0.5, 0.5]
92+
radii[0] = r_center
93+
94+
# 2. First ring: 6 circles in hexagonal arrangement
95+
r_ring1 = 0.1035
96+
ring1_distance = r_center + r_ring1 + 0.0005 # Small gap for stability
97+
for i in range(6):
98+
angle = 2 * np.pi * i / 6
99+
centers[i+1] = [
100+
0.5 + ring1_distance * np.cos(angle),
101+
0.5 + ring1_distance * np.sin(angle)
102+
]
103+
radii[i+1] = r_ring1
104+
```
105+
106+
The key innovations at this stage included:
107+
- A carefully tuned hexagonal arrangement for the first ring
108+
- Strategic placement of corner circles
109+
- An additional optimization step to maximize each circle's radius
110+
111+
This approach achieved a sum of radii of approximately 1.795.
112+
113+
![Generation 10 Packing](circle_packing_10.png)
114+
115+
### Generation 100: Grid-Based Approach
116+
117+
By generation 100, OpenEvolve had pivoted to a grid-based approach with variable sized circles:
118+
119+
```python
120+
# Generation 100
121+
# Row 1: 5 circles
122+
centers[0] = [0.166, 0.166]
123+
centers[1] = [0.333, 0.166]
124+
centers[2] = [0.500, 0.166]
125+
centers[3] = [0.667, 0.166]
126+
centers[4] = [0.834, 0.166]
127+
128+
# Row 2: 6 circles (staggered)
129+
centers[5] = [0.100, 0.333]
130+
centers[6] = [0.266, 0.333]
131+
# ... additional circles
132+
```
133+
134+
Key innovations:
135+
- Grid-like pattern with staggered rows
136+
- Variable circle sizes based on position (larger in the center)
137+
- More aggressive optimization routine with 50 iterations
138+
139+
This approach achieved a sum of radii of approximately 2.201.
140+
141+
![Generation 100 Packing](circle_packing_190.png)
142+
143+
### Final Solution: Mathematical Optimization
144+
145+
The breakthrough came when OpenEvolve discovered the power of mathematical optimization techniques. The final solution uses:
146+
147+
```python
148+
# Final solution with scipy.optimize
149+
def construct_packing():
150+
# ... initialization code ...
151+
152+
# Objective function: Negative sum of radii (to maximize)
153+
def objective(x):
154+
centers = x[:2*n].reshape(n, 2)
155+
radii = x[2*n:]
156+
return -np.sum(radii)
157+
158+
# Constraint: No overlaps and circles stay within the unit square
159+
def constraint(x):
160+
centers = x[:2*n].reshape(n, 2)
161+
radii = x[2*n:]
162+
163+
# Overlap constraint
164+
overlap_constraints = []
165+
for i in range(n):
166+
for j in range(i + 1, n):
167+
dist = np.sqrt(np.sum((centers[i] - centers[j])**2))
168+
overlap_constraints.append(dist - (radii[i] + radii[j]))
169+
# ... boundary constraints ...
170+
171+
# Optimization using SLSQP
172+
result = minimize(objective, x0, method='SLSQP', bounds=bounds, constraints=constraints)
173+
```
174+
175+
The key innovation in the final solution:
176+
- Using `scipy.optimize.minimize` with SLSQP method to find the optimal configuration
177+
- Formulating circle packing as a constrained optimization problem
178+
- Representing both circle positions and radii as optimization variables
179+
- Carefully crafted constraints to enforce non-overlap and boundary conditions
180+
181+
This approach achieved a sum of radii of 2.634, matching the AlphaEvolve paper's result of 2.635 to within 0.04%!
182+
183+
![Final Packing Solution](circle_packing_460.png)
184+
185+
## Results
186+
187+
Our final solution achieves:
188+
189+
```
190+
Sum of radii: 2.634292402141039
191+
Target ratio: 0.9997314619131079 (99.97% of AlphaEvolve's result)
192+
```
193+
194+
This demonstrates that OpenEvolve can successfully reproduce the results from the AlphaEvolve paper on this mathematical optimization problem.
195+
196+
## Key Observations
197+
198+
The evolution process demonstrated several interesting patterns:
199+
200+
1. **Algorithm Transition**: OpenEvolve discovered increasingly sophisticated algorithms, from basic geometric constructions to advanced mathematical optimization techniques.
201+
202+
2. **Exploration-Exploitation Balance**: The two-phase approach was crucial - initial exploration of different patterns followed by exploitation and refinement of the most promising approaches.
203+
204+
3. **Breakthrough Discoveries**: The most significant improvements came from fundamental changes in approach (e.g., switching from manual construction to mathematical optimization), not just parameter tuning.
205+
206+
4. **Code Complexity Evolution**: As the solutions improved, the code grew in complexity, adopting more sophisticated mathematical techniques.
207+
208+
## Running the Example
209+
210+
To reproduce our results:
211+
212+
```bash
213+
# Phase 1: Initial exploration
214+
python openevolve-run.py examples/circle_packing/initial_program.py \
215+
examples/circle_packing/evaluator.py \
216+
--config examples/circle_packing/config_phase_1.yaml \
217+
--iterations 100
218+
219+
# Phase 2: Breaking through the plateau
220+
python openevolve-run.py examples/circle_packing/openevolve_output/checkpoints/checkpoint_100/best_program.py \
221+
examples/circle_packing/evaluator.py \
222+
--config examples/circle_packing/config_phase_2.yaml \
223+
--iterations 100
224+
```
225+
226+
To visualize the best solution:
227+
228+
```python
229+
from examples.circle_packing.openevolve_output.best.best_program import run_packing, visualize
230+
231+
centers, radii, sum_radii = run_packing()
232+
print(f"Sum of radii: {sum_radii}")
233+
visualize(centers, radii)
234+
```
235+
236+
## Conclusion
237+
238+
This example demonstrates OpenEvolve's ability to discover sophisticated algorithms for mathematical optimization problems. By evolving from simple constructive approaches to advanced numerical optimization techniques, OpenEvolve was able to match the results reported in the AlphaEvolve paper.
239+
240+
The circle packing problem shows how OpenEvolve can discover not just improvements to existing algorithms, but entirely new algorithmic approaches, transitioning from manual geometric construction to principled mathematical optimization.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# EVOLVE-BLOCK-START
2+
"""Constructor-based circle packing for n=26 circles (5 hex rows + 3 boundary fillers)"""
3+
import numpy as np
4+
5+
def construct_packing():
6+
# Base hex parameters: 5 rows with counts [5,4,5,4,5] at radius r≈0.1
7+
eps = 1e-9
8+
r = 0.1 - 1e-6
9+
s = 2 * r
10+
v = np.sqrt(3) * r
11+
12+
centers = []
13+
radii = []
14+
15+
# 23 base circles: rows j=0..4; even rows have 5, odd rows have 4
16+
for j in range(5):
17+
y = r + j * v
18+
if j % 2 == 0:
19+
xs = r + s * np.arange(5) # 5 circles
20+
else:
21+
xs = 2 * r + s * np.arange(4) # 4 circles
22+
for x in xs:
23+
centers.append([x, y])
24+
radii.append(r)
25+
26+
# Extra 1: top cap centered above the middle gap of the top row, tangent to top boundary and two neighbors
27+
y_top = r + 4 * v
28+
dy0 = 1.0 - y_top
29+
r_top = (dy0 * dy0) / (2.0 * (dy0 + r)) - eps
30+
centers.append([6.0 * r, 1.0 - r_top])
31+
radii.append(r_top)
32+
33+
# Side fillers: tangent to a side wall and to two adjacent base circles in rows j=2 and j=3
34+
# Closed-form for side radius Re = r * (9 - 6*sqrt(2))
35+
r_side = r * (9.0 - 6.0 * np.sqrt(2.0)) - eps
36+
y2 = r + 2 * v # row j=2 (even)
37+
y_side = y2 + 2.0 * np.sqrt(r * r_side)
38+
39+
# Extra 2: left wall filler
40+
centers.append([r_side, y_side])
41+
radii.append(r_side)
42+
43+
# Extra 3: right wall filler
44+
centers.append([1.0 - r_side, y_side])
45+
radii.append(r_side)
46+
47+
centers = np.array(centers, dtype=float)
48+
radii = np.array(radii, dtype=float)
49+
return centers, radii, float(np.sum(radii))
50+
# EVOLVE-BLOCK-END
51+
52+
53+
# This part remains fixed (not evolved)
54+
def run_packing():
55+
"""Run the circle packing constructor for n=26"""
56+
centers, radii, sum_radii = construct_packing()
57+
return centers, radii, sum_radii
58+
59+
60+
def visualize(centers, radii):
61+
"""
62+
Visualize the circle packing
63+
64+
Args:
65+
centers: np.array of shape (n, 2) with (x, y) coordinates
66+
radii: np.array of shape (n) with radius of each circle
67+
"""
68+
import matplotlib.pyplot as plt
69+
from matplotlib.patches import Circle
70+
71+
fig, ax = plt.subplots(figsize=(8, 8))
72+
73+
# Draw unit square
74+
ax.set_xlim(0, 1)
75+
ax.set_ylim(0, 1)
76+
ax.set_aspect("equal")
77+
ax.grid(True)
78+
79+
# Draw circles
80+
for i, (center, radius) in enumerate(zip(centers, radii)):
81+
circle = Circle(center, radius, alpha=0.5)
82+
ax.add_patch(circle)
83+
ax.text(center[0], center[1], str(i), ha="center", va="center")
84+
85+
plt.title(f"Circle Packing (n={len(centers)}, sum={sum(radii):.6f})")
86+
plt.show()
87+
88+
89+
if __name__ == "__main__":
90+
centers, radii, sum_radii = run_packing()
91+
print(f"Sum of radii: {sum_radii}")
92+
# AlphaEvolve improved this to 2.635
93+
94+
# Uncomment to visualize:
95+
visualize(centers, radii)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"id": "081287e7-617c-4fbd-932c-566bc47827e6",
3+
"generation": 2,
4+
"iteration": 10,
5+
"current_iteration": 10,
6+
"metrics": {
7+
"validity": 1.0,
8+
"sum_radii": 2.4727904211504157,
9+
"target_ratio": 0.9384403875333647,
10+
"combined_score": 0.9384403875333647,
11+
"eval_time": 0.10989785194396973
12+
},
13+
"language": "python",
14+
"timestamp": 1764107953.884554,
15+
"saved_at": 1764107953.903265
16+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"island_feature_maps": [{"5-0": "4729e582-068c-4351-bf48-ad07e9106ae8", "0-5": "bbc93d74-31ad-4b42-9fa3-47261dacd215", "0-0": "12218e4b-302c-45c4-8777-2ea0212b20cf", "7-0": "07a4c40f-72f0-40f1-892b-9b5455d1c286", "1-0": "a33bc75f-6e8f-4713-a03f-0100f8578774", "3-0": "081287e7-617c-4fbd-932c-566bc47827e6", "7-2": "17296b5b-f0e0-44d9-9df7-a5718801246a", "0-1": "c24543c7-3e77-4b14-aeb7-f053e3e86ac0"}, {}, {}, {}], "islands": [["c24543c7-3e77-4b14-aeb7-f053e3e86ac0", "081287e7-617c-4fbd-932c-566bc47827e6", "a33bc75f-6e8f-4713-a03f-0100f8578774", "12218e4b-302c-45c4-8777-2ea0212b20cf", "104bdb8e-4d64-479b-84c7-834258d289cf", "17296b5b-f0e0-44d9-9df7-a5718801246a", "c96b4c0b-2a34-4683-b4ca-cd4943d4ba63", "4d6844ef-73f8-4b22-bc30-920b8736a8aa", "bbc93d74-31ad-4b42-9fa3-47261dacd215", "07a4c40f-72f0-40f1-892b-9b5455d1c286", "4729e582-068c-4351-bf48-ad07e9106ae8"], ["a566ffe9-5599-4975-b096-5530385b4d60"], [], ["784810f9-7415-427b-850f-aed5a28d231a"]], "archive": ["c24543c7-3e77-4b14-aeb7-f053e3e86ac0", "081287e7-617c-4fbd-932c-566bc47827e6", "a33bc75f-6e8f-4713-a03f-0100f8578774", "12218e4b-302c-45c4-8777-2ea0212b20cf", "104bdb8e-4d64-479b-84c7-834258d289cf", "17296b5b-f0e0-44d9-9df7-a5718801246a", "c96b4c0b-2a34-4683-b4ca-cd4943d4ba63", "4d6844ef-73f8-4b22-bc30-920b8736a8aa", "bbc93d74-31ad-4b42-9fa3-47261dacd215", "07a4c40f-72f0-40f1-892b-9b5455d1c286", "4729e582-068c-4351-bf48-ad07e9106ae8"], "best_program_id": "081287e7-617c-4fbd-932c-566bc47827e6", "island_best_programs": ["081287e7-617c-4fbd-932c-566bc47827e6", null, null, null], "last_iteration": 10, "current_island": 2, "island_generations": [4, 4, 3, 2], "last_migration_generation": 0, "feature_stats": {"complexity": {"min": 2162.0, "max": 3873.0, "values": [3873.0, 2486.0, 2579.0, 3494.0, 3304.0, 2375.0, 3494.0, 2375.0, 2486.0, 3494.0, 3304.0, 3133.0, 2486.0, 2375.0, 3133.0, 2486.0, 3494.0, 3304.0, 2610.0, 2610.0, 2610.0, 2375.0, 3133.0, 2486.0, 3494.0, 3304.0, 2889.0, 3439.0, 2390.0, 2162.0, 2271.0, 2791.0]}, "diversity": {"min": 203.40666666666667, "max": 652.7, "values": [652.7, 337.84999999999997, 352.73333333333335, 286.3, 300.45, 352.73333333333335, 300.45, 652.7, 352.73333333333335, 286.3, 245.9, 652.7, 300.45, 245.9, 652.7, 352.73333333333335, 286.3, 228.0375, 228.0375, 228.0375, 300.45, 245.9, 652.7, 352.73333333333335, 286.3, 210.6888888888889, 302.4818181818182, 208.85833333333332, 284.6692307692308, 229.6357142857143, 203.40666666666667]}}}

examples/circle_packing2/ablation_adaptive_exploration_gpt5_1_uniform/checkpoints/checkpoint_10/programs/07a4c40f-72f0-40f1-892b-9b5455d1c286.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

examples/circle_packing2/ablation_adaptive_exploration_gpt5_1_uniform/checkpoints/checkpoint_10/programs/081287e7-617c-4fbd-932c-566bc47827e6.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

examples/circle_packing2/ablation_adaptive_exploration_gpt5_1_uniform/checkpoints/checkpoint_10/programs/0f412fab-908f-40a7-bf69-8656e3fb8e30.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

examples/circle_packing2/ablation_adaptive_exploration_gpt5_1_uniform/checkpoints/checkpoint_10/programs/104bdb8e-4d64-479b-84c7-834258d289cf.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)