Skip to content

Commit 2696912

Browse files
committed
finialize example
1 parent 3dca845 commit 2696912

File tree

6 files changed

+215
-40
lines changed

6 files changed

+215
-40
lines changed

examples/circle_packing/README.md

Lines changed: 215 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,240 @@
1-
# Constructor-Based Circle Packing Example (n=26)
1+
# Circle Packing Example
22

3-
This example attempts to replicate one of the specific results from the AlphaEvolve paper (Section B.12): packing 26 circles inside a unit square to maximize the sum of their radii.
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.
44

5-
## Problem Description
5+
## Problem Overview
66

7-
The problem is to pack 26 disjoint circles inside a unit square so as to maximize the sum of their radii. The circles must:
8-
- Lie entirely within the unit square [0,1] × [0,1]
9-
- Not overlap with each other
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:
108

11-
According to the paper, AlphaEvolve improved the state of the art for n=26 from 2.634 to 2.635.
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
1213

13-
## Constructor-Based Approach
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.
1415

15-
Following insights from the AlphaEvolve paper, we use a constructor-based approach rather than a search algorithm:
16+
## Our Approach
1617

17-
> "For problems with highly symmetric solutions it is advantageous to evolve constructor functions as these tend to be more concise." - AlphaEvolve paper, Section 2.1
18+
We structured our evolution in two phases, each with a different configuration to encourage exploration and exploitation at different stages:
1819

19-
Instead of evolving a search algorithm that tries different configurations, we evolve a function that directly constructs a specific packing arrangement. This approach:
20+
### Phase 1: Initial Exploration
2021

21-
1. Is more deterministic (produces the same output each time)
22-
2. Can leverage geometric knowledge about optimal packings
23-
3. Tends to be more concise and easier to evolve
24-
4. Works well for problems with inherent structure or symmetry
22+
In the first phase, we focused on exploring different fundamental approaches to the packing problem:
2523

26-
## Running the Example
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
2727

28-
```bash
29-
python openevolve-run.py examples/circle_packing/initial_program.py examples/circle_packing/evaluator.py --config examples/circle_packing/config.yaml --iterations 200
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)]
3075
```
3176
32-
## Evolved Constructor Functions
77+
This approach yielded a sum of radii of approximately 0.959.
3378
34-
The evolution might discover various pattern-based approaches:
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+
```
35133

36-
1. **Concentric rings**: Placing circles in concentric rings around a central circle
37-
2. **Hexagonal patterns**: Portions of a hexagonal lattice (theoretically optimal for infinite packings)
38-
3. **Mixed-size arrangements**: Varying circle sizes to better utilize space near the boundaries
39-
4. **Specialized patterns**: Custom arrangements specific to n=26
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
40138

41-
## Evaluation Metrics
139+
This approach achieved a sum of radii of approximately 2.201.
42140

43-
The evaluator calculates several metrics:
44-
- `sum_radii`: The sum of radii achieved by the constructor
45-
- `target_ratio`: Ratio of achieved sum to target (2.635)
46-
- `validity`: Confirms circles don't overlap and stay within bounds
47-
- `combined_score`: A weighted combination of metrics (main fitness metric)
141+
![Generation 100 Packing](circle_packing_190.png)
48142

49-
## Visualization
143+
### Final Solution: Mathematical Optimization
50144

51-
The program includes a visualization function to see the constructed packing:
145+
The breakthrough came when OpenEvolve discovered the power of mathematical optimization techniques. The final solution uses:
52146

53147
```python
54-
# Add this to the end of the best program
55-
if __name__ == "__main__":
56-
centers, radii, sum_radii = run_packing()
57-
print(f"Sum of radii: {sum_radii}")
58-
visualize(centers, radii)
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)
59234
```
60235

61-
## What to Expect
236+
## Conclusion
62237

63-
The evolution process should discover increasingly better constructor functions, with several possible patterns emerging. Given enough iterations, it should approach or exceed the 2.635 value achieved in the paper.
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.
64239

65-
Different runs may converge to different packing strategies, as multiple near-optimal arrangements are possible for this problem.
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.
42.1 KB
Loading
60.3 KB
Loading
68.1 KB
Loading
73.2 KB
Loading
File renamed without changes.

0 commit comments

Comments
 (0)