33import numpy as np
44from scipy .optimize import minimize
55
6+
67def construct_packing ():
78 """
89 Construct an optimized arrangement of 26 circles in a unit square
910 using mathematical principles and optimization techniques.
10-
11+
1112 Returns:
1213 Tuple of (centers, radii, sum_of_radii)
1314 centers: np.array of shape (26, 2) with (x, y) coordinates
1415 radii: np.array of shape (26) with radius of each circle
1516 sum_of_radii: Sum of all radii
1617 """
1718 n = 26
18-
19+
1920 # Initial guess: Strategic placement with some randomness
2021 centers = np .zeros ((n , 2 ))
2122 radii = np .zeros (n )
2223
2324 # Heuristic placement for better initial guess: place larger circles in center
24- radii [:] = np .linspace (0.12 , 0.05 , n ) # Linear distribution of radii
25-
25+ radii [:] = np .linspace (0.12 , 0.05 , n ) # Linear distribution of radii
26+
2627 # Initial placement: approximate hexagonal grid
2728 grid_x = int (np .sqrt (n ))
2829 grid_y = int (n / grid_x )
29-
30+
3031 x_coords = np .linspace (0.15 , 0.85 , grid_x )
3132 y_coords = np .linspace (0.15 , 0.85 , grid_y )
32-
33+
3334 count = 0
3435 for i in range (grid_x ):
3536 for j in range (grid_y ):
3637 if count < n :
3738 centers [count ] = [x_coords [i ] + 0.05 * (j % 2 ), y_coords [j ]]
3839 count += 1
39-
40+
4041 # Place remaining circles randomly
4142 while count < n :
4243 centers [count ] = np .random .rand (2 ) * 0.7 + 0.15
4344 count += 1
4445
4546 # Objective function: Negative sum of radii (to maximize)
4647 def objective (x ):
47- centers = x [:2 * n ].reshape (n , 2 )
48- radii = x [2 * n :]
48+ centers = x [: 2 * n ].reshape (n , 2 )
49+ radii = x [2 * n :]
4950 return - np .sum (radii )
5051
5152 # Constraint: No overlaps and circles stay within the unit square
5253 def constraint (x ):
53- centers = x [:2 * n ].reshape (n , 2 )
54- radii = x [2 * n :]
55-
54+ centers = x [: 2 * n ].reshape (n , 2 )
55+ radii = x [2 * n :]
56+
5657 # Overlap constraint
5758 overlap_constraints = []
5859 for i in range (n ):
5960 for j in range (i + 1 , n ):
60- dist = np .sqrt (np .sum ((centers [i ] - centers [j ])** 2 ))
61+ dist = np .sqrt (np .sum ((centers [i ] - centers [j ]) ** 2 ))
6162 overlap_constraints .append (dist - (radii [i ] + radii [j ]))
62-
63+
6364 # Boundary constraints
6465 boundary_constraints = []
6566 for i in range (n ):
6667 boundary_constraints .append (centers [i , 0 ] - radii [i ]) # x >= radius
67- boundary_constraints .append (1 - centers [i , 0 ] - radii [i ]) # x <= 1 - radius
68+ boundary_constraints .append (1 - centers [i , 0 ] - radii [i ]) # x <= 1 - radius
6869 boundary_constraints .append (centers [i , 1 ] - radii [i ]) # y >= radius
69- boundary_constraints .append (1 - centers [i , 1 ] - radii [i ]) # y <= 1 - radius
70-
70+ boundary_constraints .append (1 - centers [i , 1 ] - radii [i ]) # y <= 1 - radius
71+
7172 return np .array (overlap_constraints + boundary_constraints )
7273
7374 # Initial guess vector
7475 x0 = np .concatenate ([centers .flatten (), radii ])
7576
7677 # Bounds: Circles stay within the unit square and radii are positive
77- bounds = [(0 , 1 )] * (2 * n ) + [(0.03 , 0.2 )] * n # radii are positive, up to 0.2
78+ bounds = [(0 , 1 )] * (2 * n ) + [(0.03 , 0.2 )] * n # radii are positive, up to 0.2
7879
7980 # Constraints dictionary
80- constraints = {' type' : ' ineq' , ' fun' : constraint }
81+ constraints = {" type" : " ineq" , " fun" : constraint }
8182
8283 # Optimization using SLSQP
83- result = minimize (objective , x0 , method = 'SLSQP' , bounds = bounds , constraints = constraints , options = {'maxiter' : 1000 , 'ftol' : 1e-8 })
84+ result = minimize (
85+ objective ,
86+ x0 ,
87+ method = "SLSQP" ,
88+ bounds = bounds ,
89+ constraints = constraints ,
90+ options = {"maxiter" : 1000 , "ftol" : 1e-8 },
91+ )
8492
8593 # Extract optimized centers and radii
86- optimized_centers = result .x [:2 * n ].reshape (n , 2 )
87- optimized_radii = result .x [2 * n :]
94+ optimized_centers = result .x [: 2 * n ].reshape (n , 2 )
95+ optimized_radii = result .x [2 * n :]
8896
8997 # Ensure radii are not negative (numerical stability)
9098 optimized_radii = np .maximum (optimized_radii , 0.001 )
@@ -93,46 +101,51 @@ def constraint(x):
93101 sum_radii = np .sum (optimized_radii )
94102
95103 return optimized_centers , optimized_radii , sum_radii
104+
105+
96106# EVOLVE-BLOCK-END
97107
108+
98109# This part remains fixed (not evolved)
99110def run_packing ():
100111 """Run the circle packing constructor for n=26"""
101112 centers , radii , sum_radii = construct_packing ()
102113 return centers , radii , sum_radii
103114
115+
104116def visualize (centers , radii ):
105117 """
106118 Visualize the circle packing
107-
119+
108120 Args:
109121 centers: np.array of shape (n, 2) with (x, y) coordinates
110122 radii: np.array of shape (n) with radius of each circle
111123 """
112124 import matplotlib .pyplot as plt
113125 from matplotlib .patches import Circle
114-
126+
115127 fig , ax = plt .subplots (figsize = (8 , 8 ))
116-
128+
117129 # Draw unit square
118130 ax .set_xlim (0 , 1 )
119131 ax .set_ylim (0 , 1 )
120- ax .set_aspect (' equal' )
132+ ax .set_aspect (" equal" )
121133 ax .grid (True )
122-
134+
123135 # Draw circles
124136 for i , (center , radius ) in enumerate (zip (centers , radii )):
125137 circle = Circle (center , radius , alpha = 0.5 )
126138 ax .add_patch (circle )
127- ax .text (center [0 ], center [1 ], str (i ), ha = ' center' , va = ' center' )
128-
139+ ax .text (center [0 ], center [1 ], str (i ), ha = " center" , va = " center" )
140+
129141 plt .title (f"Circle Packing (n={ len (centers )} , sum={ sum (radii ):.6f} )" )
130142 plt .show ()
131143
144+
132145if __name__ == "__main__" :
133146 centers , radii , sum_radii = run_packing ()
134147 print (f"Sum of radii: { sum_radii } " )
135148 # AlphaEvolve improved this to 2.635
136-
149+
137150 # Uncomment to visualize:
138- # visualize(centers, radii)
151+ # visualize(centers, radii)
0 commit comments