Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/__pycache__/main.cpython-311.pyc +0 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/edit.diff +415 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/main.py +262 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/original.py +184 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/correct.json +4 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/job_log.err +11 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/job_log.out +18 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/metrics.json +16 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/rewrite.txt +253 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/__pycache__/main.cpython-311.pyc +0 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/correct.json +4 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/job_log.err +9 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/job_log.out +18 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/metrics.json +16 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/__pycache__/main.cpython-311.pyc +0 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/correct.json +4 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/job_log.err +9 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/job_log.out +18 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/metrics.json +16 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/__pycache__/main.cpython-311.pyc +0 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/edit.diff +125 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/main.py +106 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/original.py +94 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/correct.json +4 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/job_log.err +9 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/job_log.out +18 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/metrics.json +16 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/search_replace.txt +122 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/__pycache__/main.cpython-311.pyc +0 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/edit.diff +220 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/main.py +214 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/original.py +186 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/correct.json +4 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/job_log.err +9 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/job_log.out +18 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/metrics.json +16 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/search_replace.txt +100 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/__pycache__/main.cpython-311.pyc +0 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/correct.json +4 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/job_log.err +9 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/job_log.out +18 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/metrics.json +16 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/__pycache__/main.cpython-311.pyc +0 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/edit.diff +239 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/main.py +229 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/original.py +191 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/correct.json +4 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/job_log.err +9 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/job_log.out +18 -0
- examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/metrics.json +16 -0
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/__pycache__/main.cpython-311.pyc
ADDED
|
Binary file (16.3 kB). View file
|
|
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/edit.diff
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
--- a/original.py
|
| 2 |
+
+++ b/original.py
|
| 3 |
+
@@ -1,184 +1,262 @@
|
| 4 |
+
# EVOLVE-BLOCK-START
|
| 5 |
+
-"""
|
| 6 |
+
-Constructor-based circle packing for n=26 circles using a hybrid approach:
|
| 7 |
+
-a force-directed pre-relaxation followed by an advanced Simulated Annealing search.
|
| 8 |
+
-"""
|
| 9 |
+
-
|
| 10 |
+
import numpy as np
|
| 11 |
+
-
|
| 12 |
+
-def compute_max_radii(centers):
|
| 13 |
+
- """
|
| 14 |
+
- Compute the maximum possible radii for each circle position such that they
|
| 15 |
+
- don't overlap and stay within the unit square. This is an iterative version
|
| 16 |
+
- that converges to a stable solution.
|
| 17 |
+
+import math
|
| 18 |
+
+
|
| 19 |
+
+def compute_max_radii(centers, max_iterations=750):
|
| 20 |
+
+ """
|
| 21 |
+
+ Compute the maximum possible radii for each circle position
|
| 22 |
+
+ such that they don't overlap and stay within the unit square. This is
|
| 23 |
+
+ an iterative version that converges to a stable solution.
|
| 24 |
+
"""
|
| 25 |
+
n = centers.shape[0]
|
| 26 |
+
- # Initialize radii based on distance to boundaries (vectorized)
|
| 27 |
+
radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0)
|
| 28 |
+
-
|
| 29 |
+
- # Iteratively resolve overlaps until convergence
|
| 30 |
+
- for _ in range(500):
|
| 31 |
+
+ for _ in range(max_iterations):
|
| 32 |
+
changes_made = False
|
| 33 |
+
for i in range(n):
|
| 34 |
+
for j in range(i + 1, n):
|
| 35 |
+
dist = np.linalg.norm(centers[i] - centers[j])
|
| 36 |
+
if radii[i] + radii[j] > dist + 1e-12:
|
| 37 |
+
sum_r = radii[i] + radii[j]
|
| 38 |
+
if sum_r > 1e-12:
|
| 39 |
+
scale = dist / sum_r
|
| 40 |
+
ri_new, rj_new = radii[i] * scale, radii[j] * scale
|
| 41 |
+
if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12:
|
| 42 |
+
radii[i], radii[j] = ri_new, rj_new
|
| 43 |
+
changes_made = True
|
| 44 |
+
- elif radii[i] > 0 or radii[j] > 0:
|
| 45 |
+
- radii[i], radii[j] = 0, 0
|
| 46 |
+
- changes_made = True
|
| 47 |
+
if not changes_made:
|
| 48 |
+
break
|
| 49 |
+
return radii
|
| 50 |
+
|
| 51 |
+
-def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin):
|
| 52 |
+
- """
|
| 53 |
+
- Applies a force-directed relaxation algorithm to settle circle centers.
|
| 54 |
+
- Circles repel each other and are repelled by boundaries.
|
| 55 |
+
- """
|
| 56 |
+
- n = centers.shape[0]
|
| 57 |
+
- for _ in range(iterations):
|
| 58 |
+
- forces = np.zeros_like(centers)
|
| 59 |
+
- for i in range(n):
|
| 60 |
+
- # Circle-circle repulsion
|
| 61 |
+
- for j in range(i + 1, n):
|
| 62 |
+
- vec = centers[i] - centers[j]
|
| 63 |
+
- dist = np.linalg.norm(vec)
|
| 64 |
+
- if 0 < dist < repulsion_threshold:
|
| 65 |
+
- force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist
|
| 66 |
+
- force_vec = force_magnitude * (vec / dist)
|
| 67 |
+
- forces[i] += force_vec
|
| 68 |
+
- forces[j] -= force_vec
|
| 69 |
+
- # Boundary repulsion
|
| 70 |
+
- x, y = centers[i]
|
| 71 |
+
- if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x)
|
| 72 |
+
- if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin))
|
| 73 |
+
- if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y)
|
| 74 |
+
- if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin))
|
| 75 |
+
- centers += step_size * forces
|
| 76 |
+
- centers = np.clip(centers, 0.0, 1.0)
|
| 77 |
+
- return centers
|
| 78 |
+
+
|
| 79 |
+
+class CirclePackingOrchestrator:
|
| 80 |
+
+ """
|
| 81 |
+
+ Manages a multi-stage circle packing pipeline, structured for clarity and performance.
|
| 82 |
+
+
|
| 83 |
+
+ This orchestrator class encapsulates the entire process, from finding a promising
|
| 84 |
+
+ initial configuration via a multi-start strategy to refining it with an advanced
|
| 85 |
+
+ Simulated Annealing algorithm and final polishing. This structure separates concerns,
|
| 86 |
+
+ making the process more modular and maintainable.
|
| 87 |
+
+ """
|
| 88 |
+
+ def __init__(self, n=26):
|
| 89 |
+
+ self.n = n
|
| 90 |
+
+ self.centers = np.zeros((n, 2))
|
| 91 |
+
+ self.best_centers = None
|
| 92 |
+
+ self.best_radii = None
|
| 93 |
+
+ self.best_sum_radii = -1.0
|
| 94 |
+
+
|
| 95 |
+
+ def _generate_void_config(self, void_center, amplitude, sigma):
|
| 96 |
+
+ """Helper to generate initial centers from a grid deformed by a Gaussian push."""
|
| 97 |
+
+ x_coords = np.linspace(0.1, 0.9, 5)
|
| 98 |
+
+ y_coords = np.linspace(0.1, 0.9, 5)
|
| 99 |
+
+ xx, yy = np.meshgrid(x_coords, y_coords)
|
| 100 |
+
+ base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T
|
| 101 |
+
+
|
| 102 |
+
+ displacements = base_centers_25 - void_center
|
| 103 |
+
+ distances = np.linalg.norm(displacements, axis=1)
|
| 104 |
+
+ mask = distances > 1e-9
|
| 105 |
+
+
|
| 106 |
+
+ push_magnitudes = np.zeros(25)
|
| 107 |
+
+ if np.any(mask):
|
| 108 |
+
+ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2))
|
| 109 |
+
+ displacements[mask] /= distances[mask, np.newaxis]
|
| 110 |
+
+
|
| 111 |
+
+ initial_centers = np.zeros((self.n, 2))
|
| 112 |
+
+ initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis]
|
| 113 |
+
+ initial_centers[25] = void_center
|
| 114 |
+
+ return np.clip(initial_centers, 0.0, 1.0)
|
| 115 |
+
+
|
| 116 |
+
+
|
| 117 |
+
+ def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin):
|
| 118 |
+
+ """Performs a vectorized force-directed relaxation phase for speed."""
|
| 119 |
+
+ for _ in range(iters):
|
| 120 |
+
+ diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :]
|
| 121 |
+
+ dists = np.linalg.norm(diff, axis=2)
|
| 122 |
+
+ np.fill_diagonal(dists, np.inf)
|
| 123 |
+
+
|
| 124 |
+
+ repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9)
|
| 125 |
+
+
|
| 126 |
+
+ force_magnitudes = np.zeros_like(dists)
|
| 127 |
+
+ force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask]
|
| 128 |
+
+
|
| 129 |
+
+ normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0)
|
| 130 |
+
+ forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1)
|
| 131 |
+
+
|
| 132 |
+
+ forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0])
|
| 133 |
+
+ forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin))
|
| 134 |
+
+ forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1])
|
| 135 |
+
+ forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin))
|
| 136 |
+
+
|
| 137 |
+
+ self.centers += step_size * forces
|
| 138 |
+
+ self.centers = np.clip(self.centers, 0.0, 1.0)
|
| 139 |
+
+
|
| 140 |
+
+ def _initialize_and_select_best_start(self, num_starts=8):
|
| 141 |
+
+ """
|
| 142 |
+
+ Runs a multi-start initialization. Generates several random starting
|
| 143 |
+
+ configurations, performs a quick relaxation on each, and selects the
|
| 144 |
+
+ best one to seed the main SA optimization.
|
| 145 |
+
+ """
|
| 146 |
+
+ best_start_score = -1.0
|
| 147 |
+
+ best_start_centers = None
|
| 148 |
+
+
|
| 149 |
+
+ for _ in range(num_starts):
|
| 150 |
+
+ void_center = np.random.uniform(0.2, 0.8, 2)
|
| 151 |
+
+ amplitude = np.random.uniform(0.05, 0.1)
|
| 152 |
+
+ sigma = np.random.uniform(0.1, 0.2)
|
| 153 |
+
+ self.centers = self._generate_void_config(void_center, amplitude, sigma)
|
| 154 |
+
+
|
| 155 |
+
+ self._force_directed_relaxation_vectorized(
|
| 156 |
+
+ iters=300, step_size=0.002, repulsion_strength=0.02,
|
| 157 |
+
+ boundary_strength=0.08, repulsion_threshold=0.2, boundary_margin=0.04
|
| 158 |
+
+ )
|
| 159 |
+
+
|
| 160 |
+
+ radii = compute_max_radii(self.centers, max_iterations=100)
|
| 161 |
+
+ score = np.sum(radii)
|
| 162 |
+
+
|
| 163 |
+
+ if score > best_start_score:
|
| 164 |
+
+ best_start_score = score
|
| 165 |
+
+ best_start_centers = self.centers.copy()
|
| 166 |
+
+
|
| 167 |
+
+ self.centers = best_start_centers
|
| 168 |
+
+ self.best_centers = best_start_centers.copy()
|
| 169 |
+
+ self.best_radii = compute_max_radii(self.best_centers)
|
| 170 |
+
+ self.best_sum_radii = np.sum(self.best_radii)
|
| 171 |
+
+
|
| 172 |
+
+ def _select_circle_context_aware(self, current_radii, current_centers):
|
| 173 |
+
+ """Intelligently selects a circle to perturb."""
|
| 174 |
+
+ inverse_radii = 1 / (current_radii + 1e-8)
|
| 175 |
+
+ dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0],
|
| 176 |
+
+ current_centers[:, 1], 1 - current_centers[:, 1]], axis=0)
|
| 177 |
+
+ boundary_weight = np.exp(-dist_to_boundary / 0.08)
|
| 178 |
+
+ combined_weights = inverse_radii * (1 + boundary_weight)
|
| 179 |
+
+ selection_probs = combined_weights / np.sum(combined_weights)
|
| 180 |
+
+ return np.random.choice(self.n, p=selection_probs)
|
| 181 |
+
+
|
| 182 |
+
+ def _simulated_annealing_search(self):
|
| 183 |
+
+ """
|
| 184 |
+
+ Performs the main optimization using SA with multi-modal perturbations,
|
| 185 |
+
+ adaptive parameters, and a refined stagnation escape mechanism.
|
| 186 |
+
+ """
|
| 187 |
+
+ total_iterations = 40000
|
| 188 |
+
+ initial_temp, final_temp = 0.001, 1e-10
|
| 189 |
+
+ initial_perturb_strength, final_perturb_strength = 0.04, 0.0001
|
| 190 |
+
+
|
| 191 |
+
+ current_centers = self.centers.copy()
|
| 192 |
+
+ current_radii = self.best_radii.copy()
|
| 193 |
+
+ current_sum_radii = self.best_sum_radii
|
| 194 |
+
+
|
| 195 |
+
+ swap_prob, cluster_prob = 0.10, 0.15
|
| 196 |
+
+
|
| 197 |
+
+ stagnation_counter, stagnation_threshold = 0, 1500
|
| 198 |
+
+ perturb_boost, boost_factor, boost_decay = 1.0, 4.0, 0.97
|
| 199 |
+
+ temp_reheat_factor = 0.5
|
| 200 |
+
+
|
| 201 |
+
+ min_radii_iters, max_radii_iters = 150, 800
|
| 202 |
+
+
|
| 203 |
+
+ for iteration in range(total_iterations):
|
| 204 |
+
+ progress = iteration / total_iterations
|
| 205 |
+
+ temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress)
|
| 206 |
+
+ base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress)
|
| 207 |
+
+ radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress)
|
| 208 |
+
+
|
| 209 |
+
+ current_temp = temp_schedule
|
| 210 |
+
+ if stagnation_counter >= stagnation_threshold:
|
| 211 |
+
+ perturb_boost = boost_factor
|
| 212 |
+
+ current_temp += initial_temp * temp_reheat_factor
|
| 213 |
+
+ stagnation_counter = 0
|
| 214 |
+
+
|
| 215 |
+
+ candidate_centers = current_centers.copy()
|
| 216 |
+
+ rand_val = np.random.rand()
|
| 217 |
+
+
|
| 218 |
+
+ if rand_val < swap_prob:
|
| 219 |
+
+ if self.n > 1:
|
| 220 |
+
+ sorted_indices = np.argsort(current_radii)
|
| 221 |
+
+ num_candidates = max(1, self.n // 4)
|
| 222 |
+
+ idx_small = np.random.choice(sorted_indices[:num_candidates])
|
| 223 |
+
+ idx_large = np.random.choice(sorted_indices[-num_candidates:])
|
| 224 |
+
+ if idx_small != idx_large:
|
| 225 |
+
+ candidate_centers[idx_small], candidate_centers[idx_large] = \
|
| 226 |
+
+ candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy()
|
| 227 |
+
+
|
| 228 |
+
+ elif rand_val < swap_prob + cluster_prob:
|
| 229 |
+
+ primary_idx = self._select_circle_context_aware(current_radii, current_centers)
|
| 230 |
+
+ distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1)
|
| 231 |
+
+ distances[primary_idx] = np.inf
|
| 232 |
+
+ neighbor_indices = np.argsort(distances)[:2]
|
| 233 |
+
+ indices_to_perturb = np.append(neighbor_indices, primary_idx)
|
| 234 |
+
+
|
| 235 |
+
+ eff_strength = base_perturb_strength * perturb_boost * 0.6
|
| 236 |
+
+ displacement = np.random.uniform(-eff_strength, eff_strength, 2)
|
| 237 |
+
+ candidate_centers[indices_to_perturb] += displacement
|
| 238 |
+
+
|
| 239 |
+
+ else:
|
| 240 |
+
+ circle_idx = self._select_circle_context_aware(current_radii, current_centers)
|
| 241 |
+
+ max_r = np.max(current_radii) + 1e-8
|
| 242 |
+
+ relative_radius = current_radii[circle_idx] / max_r
|
| 243 |
+
+ perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5
|
| 244 |
+
+ eff_strength = base_perturb_strength * perturb_factor * perturb_boost
|
| 245 |
+
+ displacement = np.random.uniform(-eff_strength, eff_strength, 2)
|
| 246 |
+
+ candidate_centers[circle_idx] += displacement
|
| 247 |
+
+
|
| 248 |
+
+ candidate_centers = np.clip(candidate_centers, 0.0, 1.0)
|
| 249 |
+
+ if perturb_boost > 1.0:
|
| 250 |
+
+ perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay
|
| 251 |
+
+
|
| 252 |
+
+ candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit)
|
| 253 |
+
+ candidate_sum_radii = np.sum(candidate_radii)
|
| 254 |
+
+
|
| 255 |
+
+ delta_E = candidate_sum_radii - current_sum_radii
|
| 256 |
+
+ if delta_E > 0 or (current_temp > 1e-12 and np.random.rand() < math.exp(delta_E / current_temp)):
|
| 257 |
+
+ current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii
|
| 258 |
+
+ if current_sum_radii > self.best_sum_radii:
|
| 259 |
+
+ self.best_sum_radii = current_sum_radii
|
| 260 |
+
+ self.best_centers = current_centers.copy()
|
| 261 |
+
+ self.best_radii = current_radii.copy()
|
| 262 |
+
+ stagnation_counter = 0
|
| 263 |
+
+ else:
|
| 264 |
+
+ stagnation_counter += 1
|
| 265 |
+
+ else:
|
| 266 |
+
+ stagnation_counter += 1
|
| 267 |
+
+
|
| 268 |
+
+ self.centers = self.best_centers.copy()
|
| 269 |
+
+
|
| 270 |
+
+
|
| 271 |
+
+ def pack(self):
|
| 272 |
+
+ """Executes the full, orchestrated packing pipeline."""
|
| 273 |
+
+ self._initialize_and_select_best_start(num_starts=8)
|
| 274 |
+
+
|
| 275 |
+
+ self._simulated_annealing_search()
|
| 276 |
+
+
|
| 277 |
+
+ self.centers = self.best_centers.copy()
|
| 278 |
+
+ self._force_directed_relaxation_vectorized(
|
| 279 |
+
+ iters=500, step_size=0.0001, repulsion_strength=0.001,
|
| 280 |
+
+ boundary_strength=0.01, repulsion_threshold=0.18, boundary_margin=0.02
|
| 281 |
+
+ )
|
| 282 |
+
+
|
| 283 |
+
+ final_radii = compute_max_radii(self.centers, max_iterations=1000)
|
| 284 |
+
+ final_sum_radii = np.sum(final_radii)
|
| 285 |
+
+
|
| 286 |
+
+ if final_sum_radii > self.best_sum_radii:
|
| 287 |
+
+ self.best_radii = final_radii
|
| 288 |
+
+ self.best_centers = self.centers
|
| 289 |
+
+
|
| 290 |
+
+ return self.best_centers, self.best_radii
|
| 291 |
+
+
|
| 292 |
+
|
| 293 |
+
def construct_packing():
|
| 294 |
+
"""
|
| 295 |
+
- Constructs a high-density arrangement of 26 circles. This method combines
|
| 296 |
+
- a proven asymmetric initialization, a mild force-directed pre-relaxation,
|
| 297 |
+
- and a sophisticated Simulated Annealing local search with adaptive heuristics.
|
| 298 |
+
- """
|
| 299 |
+
- n = 26
|
| 300 |
+
-
|
| 301 |
+
- # 1. Initialization: Asymmetric Gaussian-deformed grid.
|
| 302 |
+
- x_coords = np.linspace(0.1, 0.9, 5)
|
| 303 |
+
- y_coords = np.linspace(0.1, 0.9, 5)
|
| 304 |
+
- xx, yy = np.meshgrid(x_coords, y_coords)
|
| 305 |
+
- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T
|
| 306 |
+
- void_center = np.array([0.4, 0.2])
|
| 307 |
+
- amplitude, sigma = 0.06, 0.15
|
| 308 |
+
-
|
| 309 |
+
- displacements = base_centers_25 - void_center
|
| 310 |
+
- distances = np.linalg.norm(displacements, axis=1)
|
| 311 |
+
- mask = distances > 1e-9
|
| 312 |
+
- push_magnitudes = np.zeros(25)
|
| 313 |
+
- push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2))
|
| 314 |
+
- displacements[mask] /= distances[mask, np.newaxis]
|
| 315 |
+
-
|
| 316 |
+
- centers = np.zeros((n, 2))
|
| 317 |
+
- centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis]
|
| 318 |
+
- centers[25] = void_center
|
| 319 |
+
- centers = np.clip(centers, 0.0, 1.0)
|
| 320 |
+
-
|
| 321 |
+
- # 2. Pre-optimization: A mild force-directed relaxation to settle the initial state.
|
| 322 |
+
- centers = apply_force_directed_relaxation(
|
| 323 |
+
- centers, iterations=500, step_size=0.001, repulsion_strength=0.01,
|
| 324 |
+
- repulsion_threshold=0.18, boundary_strength=0.05, boundary_margin=0.03
|
| 325 |
+
- )
|
| 326 |
+
-
|
| 327 |
+
- # 3. Main Optimization: Advanced Simulated Annealing with Stagnation Escape.
|
| 328 |
+
- radii = compute_max_radii(centers)
|
| 329 |
+
-
|
| 330 |
+
- best_centers = centers.copy()
|
| 331 |
+
- best_radii = radii.copy()
|
| 332 |
+
- best_sum_radii = np.sum(radii)
|
| 333 |
+
-
|
| 334 |
+
- current_centers = centers.copy()
|
| 335 |
+
- current_radii = radii.copy()
|
| 336 |
+
- current_sum_radii = best_sum_radii
|
| 337 |
+
-
|
| 338 |
+
- # Tuned SA parameters based on high-performing ancestors for better exploration
|
| 339 |
+
- total_iterations = 15000
|
| 340 |
+
- initial_g_perturb_base = 0.04
|
| 341 |
+
- final_g_perturb = 0.0003
|
| 342 |
+
- T_initial, T_final = 0.2, 1e-7
|
| 343 |
+
-
|
| 344 |
+
- # Stagnation escape mechanism to kick search out of local optima
|
| 345 |
+
- no_improvement_count = 0
|
| 346 |
+
- max_no_improvement_steps = 500
|
| 347 |
+
- current_initial_g_perturb = initial_g_perturb_base
|
| 348 |
+
-
|
| 349 |
+
- for it in range(total_iterations):
|
| 350 |
+
- # Annealing schedules with dynamic perturbation
|
| 351 |
+
- g_perturb = current_initial_g_perturb + (final_g_perturb - current_initial_g_perturb) * (it / total_iterations)
|
| 352 |
+
- temp = T_initial * (T_final / T_initial)**(it / total_iterations)
|
| 353 |
+
-
|
| 354 |
+
- candidate_centers = current_centers.copy()
|
| 355 |
+
-
|
| 356 |
+
- # Adaptive Selection: Prioritize small circles and those near boundaries
|
| 357 |
+
- inverse_radii = 1 / (current_radii + 1e-8)
|
| 358 |
+
- dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0)
|
| 359 |
+
- boundary_weight = np.exp(-dist_to_boundary / 0.1)
|
| 360 |
+
- weights = inverse_radii * (1 + boundary_weight)
|
| 361 |
+
- probs = weights / np.sum(weights)
|
| 362 |
+
- circle_idx = np.random.choice(n, p=probs)
|
| 363 |
+
-
|
| 364 |
+
- # Adaptive Perturbation: Give larger kicks to smaller circles
|
| 365 |
+
- max_r = np.max(current_radii) + 1e-8
|
| 366 |
+
- relative_r = current_radii[circle_idx] / max_r
|
| 367 |
+
- # Increased multiplier for more aggressive small circle movement
|
| 368 |
+
- perturb_factor = 1.0 + (1.0 - relative_r) * 2.0
|
| 369 |
+
- eff_perturb = g_perturb * perturb_factor
|
| 370 |
+
-
|
| 371 |
+
- displacement = np.random.uniform(-eff_perturb, eff_perturb, 2)
|
| 372 |
+
- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0)
|
| 373 |
+
-
|
| 374 |
+
- # Evaluation and Acceptance
|
| 375 |
+
- candidate_radii = compute_max_radii(candidate_centers)
|
| 376 |
+
- candidate_sum_radii = np.sum(candidate_radii)
|
| 377 |
+
-
|
| 378 |
+
- accepted = False
|
| 379 |
+
- delta = candidate_sum_radii - current_sum_radii
|
| 380 |
+
- if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)):
|
| 381 |
+
- current_sum_radii = candidate_sum_radii
|
| 382 |
+
- current_centers = candidate_centers.copy()
|
| 383 |
+
- current_radii = candidate_radii.copy()
|
| 384 |
+
- accepted = True
|
| 385 |
+
-
|
| 386 |
+
- # Update best solution and manage stagnation
|
| 387 |
+
- if current_sum_radii > best_sum_radii:
|
| 388 |
+
- best_sum_radii = current_sum_radii
|
| 389 |
+
- best_centers = current_centers.copy()
|
| 390 |
+
- best_radii = current_radii.copy()
|
| 391 |
+
- no_improvement_count = 0 # Reset on new best
|
| 392 |
+
- elif not accepted:
|
| 393 |
+
- no_improvement_count += 1
|
| 394 |
+
- # If stagnated, boost perturbation to escape local optimum
|
| 395 |
+
- if no_improvement_count > max_no_improvement_steps:
|
| 396 |
+
- current_initial_g_perturb *= 1.2
|
| 397 |
+
- no_improvement_count = 0
|
| 398 |
+
-
|
| 399 |
+
- return best_centers, best_radii
|
| 400 |
+
+ Constructs a high-density arrangement of 26 circles by instantiating and
|
| 401 |
+
+ running the CirclePackingOrchestrator.
|
| 402 |
+
+ """
|
| 403 |
+
+ orchestrator = CirclePackingOrchestrator(n=26)
|
| 404 |
+
+ centers, radii = orchestrator.pack()
|
| 405 |
+
+ return centers, radii
|
| 406 |
+
# EVOLVE-BLOCK-END
|
| 407 |
+
|
| 408 |
+
|
| 409 |
+
# This part remains fixed (not evolved)
|
| 410 |
+
def run_packing():
|
| 411 |
+
"""Run the circle packing constructor for n=26"""
|
| 412 |
+
centers, radii = construct_packing()
|
| 413 |
+
# Calculate the sum of radii
|
| 414 |
+
sum_radii = np.sum(radii)
|
| 415 |
+
return centers, radii, sum_radii
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/main.py
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# EVOLVE-BLOCK-START
|
| 2 |
+
import numpy as np
|
| 3 |
+
import math
|
| 4 |
+
|
| 5 |
+
def compute_max_radii(centers, max_iterations=750):
|
| 6 |
+
"""
|
| 7 |
+
Compute the maximum possible radii for each circle position
|
| 8 |
+
such that they don't overlap and stay within the unit square. This is
|
| 9 |
+
an iterative version that converges to a stable solution.
|
| 10 |
+
"""
|
| 11 |
+
n = centers.shape[0]
|
| 12 |
+
radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0)
|
| 13 |
+
for _ in range(max_iterations):
|
| 14 |
+
changes_made = False
|
| 15 |
+
for i in range(n):
|
| 16 |
+
for j in range(i + 1, n):
|
| 17 |
+
dist = np.linalg.norm(centers[i] - centers[j])
|
| 18 |
+
if radii[i] + radii[j] > dist + 1e-12:
|
| 19 |
+
sum_r = radii[i] + radii[j]
|
| 20 |
+
if sum_r > 1e-12:
|
| 21 |
+
scale = dist / sum_r
|
| 22 |
+
ri_new, rj_new = radii[i] * scale, radii[j] * scale
|
| 23 |
+
if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12:
|
| 24 |
+
radii[i], radii[j] = ri_new, rj_new
|
| 25 |
+
changes_made = True
|
| 26 |
+
if not changes_made:
|
| 27 |
+
break
|
| 28 |
+
return radii
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class CirclePackingOrchestrator:
|
| 32 |
+
"""
|
| 33 |
+
Manages a multi-stage circle packing pipeline, structured for clarity and performance.
|
| 34 |
+
|
| 35 |
+
This orchestrator class encapsulates the entire process, from finding a promising
|
| 36 |
+
initial configuration via a multi-start strategy to refining it with an advanced
|
| 37 |
+
Simulated Annealing algorithm and final polishing. This structure separates concerns,
|
| 38 |
+
making the process more modular and maintainable.
|
| 39 |
+
"""
|
| 40 |
+
def __init__(self, n=26):
|
| 41 |
+
self.n = n
|
| 42 |
+
self.centers = np.zeros((n, 2))
|
| 43 |
+
self.best_centers = None
|
| 44 |
+
self.best_radii = None
|
| 45 |
+
self.best_sum_radii = -1.0
|
| 46 |
+
|
| 47 |
+
def _generate_void_config(self, void_center, amplitude, sigma):
|
| 48 |
+
"""Helper to generate initial centers from a grid deformed by a Gaussian push."""
|
| 49 |
+
x_coords = np.linspace(0.1, 0.9, 5)
|
| 50 |
+
y_coords = np.linspace(0.1, 0.9, 5)
|
| 51 |
+
xx, yy = np.meshgrid(x_coords, y_coords)
|
| 52 |
+
base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T
|
| 53 |
+
|
| 54 |
+
displacements = base_centers_25 - void_center
|
| 55 |
+
distances = np.linalg.norm(displacements, axis=1)
|
| 56 |
+
mask = distances > 1e-9
|
| 57 |
+
|
| 58 |
+
push_magnitudes = np.zeros(25)
|
| 59 |
+
if np.any(mask):
|
| 60 |
+
push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2))
|
| 61 |
+
displacements[mask] /= distances[mask, np.newaxis]
|
| 62 |
+
|
| 63 |
+
initial_centers = np.zeros((self.n, 2))
|
| 64 |
+
initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis]
|
| 65 |
+
initial_centers[25] = void_center
|
| 66 |
+
return np.clip(initial_centers, 0.0, 1.0)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin):
|
| 70 |
+
"""Performs a vectorized force-directed relaxation phase for speed."""
|
| 71 |
+
for _ in range(iters):
|
| 72 |
+
diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :]
|
| 73 |
+
dists = np.linalg.norm(diff, axis=2)
|
| 74 |
+
np.fill_diagonal(dists, np.inf)
|
| 75 |
+
|
| 76 |
+
repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9)
|
| 77 |
+
|
| 78 |
+
force_magnitudes = np.zeros_like(dists)
|
| 79 |
+
force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask]
|
| 80 |
+
|
| 81 |
+
normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0)
|
| 82 |
+
forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1)
|
| 83 |
+
|
| 84 |
+
forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0])
|
| 85 |
+
forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin))
|
| 86 |
+
forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1])
|
| 87 |
+
forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin))
|
| 88 |
+
|
| 89 |
+
self.centers += step_size * forces
|
| 90 |
+
self.centers = np.clip(self.centers, 0.0, 1.0)
|
| 91 |
+
|
| 92 |
+
def _initialize_and_select_best_start(self, num_starts=8):
|
| 93 |
+
"""
|
| 94 |
+
Runs a multi-start initialization. Generates several random starting
|
| 95 |
+
configurations, performs a quick relaxation on each, and selects the
|
| 96 |
+
best one to seed the main SA optimization.
|
| 97 |
+
"""
|
| 98 |
+
best_start_score = -1.0
|
| 99 |
+
best_start_centers = None
|
| 100 |
+
|
| 101 |
+
for _ in range(num_starts):
|
| 102 |
+
void_center = np.random.uniform(0.2, 0.8, 2)
|
| 103 |
+
amplitude = np.random.uniform(0.05, 0.1)
|
| 104 |
+
sigma = np.random.uniform(0.1, 0.2)
|
| 105 |
+
self.centers = self._generate_void_config(void_center, amplitude, sigma)
|
| 106 |
+
|
| 107 |
+
self._force_directed_relaxation_vectorized(
|
| 108 |
+
iters=300, step_size=0.002, repulsion_strength=0.02,
|
| 109 |
+
boundary_strength=0.08, repulsion_threshold=0.2, boundary_margin=0.04
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
radii = compute_max_radii(self.centers, max_iterations=100)
|
| 113 |
+
score = np.sum(radii)
|
| 114 |
+
|
| 115 |
+
if score > best_start_score:
|
| 116 |
+
best_start_score = score
|
| 117 |
+
best_start_centers = self.centers.copy()
|
| 118 |
+
|
| 119 |
+
self.centers = best_start_centers
|
| 120 |
+
self.best_centers = best_start_centers.copy()
|
| 121 |
+
self.best_radii = compute_max_radii(self.best_centers)
|
| 122 |
+
self.best_sum_radii = np.sum(self.best_radii)
|
| 123 |
+
|
| 124 |
+
def _select_circle_context_aware(self, current_radii, current_centers):
|
| 125 |
+
"""Intelligently selects a circle to perturb."""
|
| 126 |
+
inverse_radii = 1 / (current_radii + 1e-8)
|
| 127 |
+
dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0],
|
| 128 |
+
current_centers[:, 1], 1 - current_centers[:, 1]], axis=0)
|
| 129 |
+
boundary_weight = np.exp(-dist_to_boundary / 0.08)
|
| 130 |
+
combined_weights = inverse_radii * (1 + boundary_weight)
|
| 131 |
+
selection_probs = combined_weights / np.sum(combined_weights)
|
| 132 |
+
return np.random.choice(self.n, p=selection_probs)
|
| 133 |
+
|
| 134 |
+
def _simulated_annealing_search(self):
|
| 135 |
+
"""
|
| 136 |
+
Performs the main optimization using SA with multi-modal perturbations,
|
| 137 |
+
adaptive parameters, and a refined stagnation escape mechanism.
|
| 138 |
+
"""
|
| 139 |
+
total_iterations = 40000
|
| 140 |
+
initial_temp, final_temp = 0.001, 1e-10
|
| 141 |
+
initial_perturb_strength, final_perturb_strength = 0.04, 0.0001
|
| 142 |
+
|
| 143 |
+
current_centers = self.centers.copy()
|
| 144 |
+
current_radii = self.best_radii.copy()
|
| 145 |
+
current_sum_radii = self.best_sum_radii
|
| 146 |
+
|
| 147 |
+
swap_prob, cluster_prob = 0.10, 0.15
|
| 148 |
+
|
| 149 |
+
stagnation_counter, stagnation_threshold = 0, 1500
|
| 150 |
+
perturb_boost, boost_factor, boost_decay = 1.0, 4.0, 0.97
|
| 151 |
+
temp_reheat_factor = 0.5
|
| 152 |
+
|
| 153 |
+
min_radii_iters, max_radii_iters = 150, 800
|
| 154 |
+
|
| 155 |
+
for iteration in range(total_iterations):
|
| 156 |
+
progress = iteration / total_iterations
|
| 157 |
+
temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress)
|
| 158 |
+
base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress)
|
| 159 |
+
radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress)
|
| 160 |
+
|
| 161 |
+
current_temp = temp_schedule
|
| 162 |
+
if stagnation_counter >= stagnation_threshold:
|
| 163 |
+
perturb_boost = boost_factor
|
| 164 |
+
current_temp += initial_temp * temp_reheat_factor
|
| 165 |
+
stagnation_counter = 0
|
| 166 |
+
|
| 167 |
+
candidate_centers = current_centers.copy()
|
| 168 |
+
rand_val = np.random.rand()
|
| 169 |
+
|
| 170 |
+
if rand_val < swap_prob:
|
| 171 |
+
if self.n > 1:
|
| 172 |
+
sorted_indices = np.argsort(current_radii)
|
| 173 |
+
num_candidates = max(1, self.n // 4)
|
| 174 |
+
idx_small = np.random.choice(sorted_indices[:num_candidates])
|
| 175 |
+
idx_large = np.random.choice(sorted_indices[-num_candidates:])
|
| 176 |
+
if idx_small != idx_large:
|
| 177 |
+
candidate_centers[idx_small], candidate_centers[idx_large] = \
|
| 178 |
+
candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy()
|
| 179 |
+
|
| 180 |
+
elif rand_val < swap_prob + cluster_prob:
|
| 181 |
+
primary_idx = self._select_circle_context_aware(current_radii, current_centers)
|
| 182 |
+
distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1)
|
| 183 |
+
distances[primary_idx] = np.inf
|
| 184 |
+
neighbor_indices = np.argsort(distances)[:2]
|
| 185 |
+
indices_to_perturb = np.append(neighbor_indices, primary_idx)
|
| 186 |
+
|
| 187 |
+
eff_strength = base_perturb_strength * perturb_boost * 0.6
|
| 188 |
+
displacement = np.random.uniform(-eff_strength, eff_strength, 2)
|
| 189 |
+
candidate_centers[indices_to_perturb] += displacement
|
| 190 |
+
|
| 191 |
+
else:
|
| 192 |
+
circle_idx = self._select_circle_context_aware(current_radii, current_centers)
|
| 193 |
+
max_r = np.max(current_radii) + 1e-8
|
| 194 |
+
relative_radius = current_radii[circle_idx] / max_r
|
| 195 |
+
perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5
|
| 196 |
+
eff_strength = base_perturb_strength * perturb_factor * perturb_boost
|
| 197 |
+
displacement = np.random.uniform(-eff_strength, eff_strength, 2)
|
| 198 |
+
candidate_centers[circle_idx] += displacement
|
| 199 |
+
|
| 200 |
+
candidate_centers = np.clip(candidate_centers, 0.0, 1.0)
|
| 201 |
+
if perturb_boost > 1.0:
|
| 202 |
+
perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay
|
| 203 |
+
|
| 204 |
+
candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit)
|
| 205 |
+
candidate_sum_radii = np.sum(candidate_radii)
|
| 206 |
+
|
| 207 |
+
delta_E = candidate_sum_radii - current_sum_radii
|
| 208 |
+
if delta_E > 0 or (current_temp > 1e-12 and np.random.rand() < math.exp(delta_E / current_temp)):
|
| 209 |
+
current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii
|
| 210 |
+
if current_sum_radii > self.best_sum_radii:
|
| 211 |
+
self.best_sum_radii = current_sum_radii
|
| 212 |
+
self.best_centers = current_centers.copy()
|
| 213 |
+
self.best_radii = current_radii.copy()
|
| 214 |
+
stagnation_counter = 0
|
| 215 |
+
else:
|
| 216 |
+
stagnation_counter += 1
|
| 217 |
+
else:
|
| 218 |
+
stagnation_counter += 1
|
| 219 |
+
|
| 220 |
+
self.centers = self.best_centers.copy()
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
def pack(self):
|
| 224 |
+
"""Executes the full, orchestrated packing pipeline."""
|
| 225 |
+
self._initialize_and_select_best_start(num_starts=8)
|
| 226 |
+
|
| 227 |
+
self._simulated_annealing_search()
|
| 228 |
+
|
| 229 |
+
self.centers = self.best_centers.copy()
|
| 230 |
+
self._force_directed_relaxation_vectorized(
|
| 231 |
+
iters=500, step_size=0.0001, repulsion_strength=0.001,
|
| 232 |
+
boundary_strength=0.01, repulsion_threshold=0.18, boundary_margin=0.02
|
| 233 |
+
)
|
| 234 |
+
|
| 235 |
+
final_radii = compute_max_radii(self.centers, max_iterations=1000)
|
| 236 |
+
final_sum_radii = np.sum(final_radii)
|
| 237 |
+
|
| 238 |
+
if final_sum_radii > self.best_sum_radii:
|
| 239 |
+
self.best_radii = final_radii
|
| 240 |
+
self.best_centers = self.centers
|
| 241 |
+
|
| 242 |
+
return self.best_centers, self.best_radii
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
def construct_packing():
|
| 246 |
+
"""
|
| 247 |
+
Constructs a high-density arrangement of 26 circles by instantiating and
|
| 248 |
+
running the CirclePackingOrchestrator.
|
| 249 |
+
"""
|
| 250 |
+
orchestrator = CirclePackingOrchestrator(n=26)
|
| 251 |
+
centers, radii = orchestrator.pack()
|
| 252 |
+
return centers, radii
|
| 253 |
+
# EVOLVE-BLOCK-END
|
| 254 |
+
|
| 255 |
+
|
| 256 |
+
# This part remains fixed (not evolved)
|
| 257 |
+
def run_packing():
|
| 258 |
+
"""Run the circle packing constructor for n=26"""
|
| 259 |
+
centers, radii = construct_packing()
|
| 260 |
+
# Calculate the sum of radii
|
| 261 |
+
sum_radii = np.sum(radii)
|
| 262 |
+
return centers, radii, sum_radii
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/original.py
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# EVOLVE-BLOCK-START
|
| 2 |
+
"""
|
| 3 |
+
Constructor-based circle packing for n=26 circles using a hybrid approach:
|
| 4 |
+
a force-directed pre-relaxation followed by an advanced Simulated Annealing search.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
|
| 9 |
+
def compute_max_radii(centers):
|
| 10 |
+
"""
|
| 11 |
+
Compute the maximum possible radii for each circle position such that they
|
| 12 |
+
don't overlap and stay within the unit square. This is an iterative version
|
| 13 |
+
that converges to a stable solution.
|
| 14 |
+
"""
|
| 15 |
+
n = centers.shape[0]
|
| 16 |
+
# Initialize radii based on distance to boundaries (vectorized)
|
| 17 |
+
radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0)
|
| 18 |
+
|
| 19 |
+
# Iteratively resolve overlaps until convergence
|
| 20 |
+
for _ in range(500):
|
| 21 |
+
changes_made = False
|
| 22 |
+
for i in range(n):
|
| 23 |
+
for j in range(i + 1, n):
|
| 24 |
+
dist = np.linalg.norm(centers[i] - centers[j])
|
| 25 |
+
if radii[i] + radii[j] > dist + 1e-12:
|
| 26 |
+
sum_r = radii[i] + radii[j]
|
| 27 |
+
if sum_r > 1e-12:
|
| 28 |
+
scale = dist / sum_r
|
| 29 |
+
ri_new, rj_new = radii[i] * scale, radii[j] * scale
|
| 30 |
+
if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12:
|
| 31 |
+
radii[i], radii[j] = ri_new, rj_new
|
| 32 |
+
changes_made = True
|
| 33 |
+
elif radii[i] > 0 or radii[j] > 0:
|
| 34 |
+
radii[i], radii[j] = 0, 0
|
| 35 |
+
changes_made = True
|
| 36 |
+
if not changes_made:
|
| 37 |
+
break
|
| 38 |
+
return radii
|
| 39 |
+
|
| 40 |
+
def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin):
|
| 41 |
+
"""
|
| 42 |
+
Applies a force-directed relaxation algorithm to settle circle centers.
|
| 43 |
+
Circles repel each other and are repelled by boundaries.
|
| 44 |
+
"""
|
| 45 |
+
n = centers.shape[0]
|
| 46 |
+
for _ in range(iterations):
|
| 47 |
+
forces = np.zeros_like(centers)
|
| 48 |
+
for i in range(n):
|
| 49 |
+
# Circle-circle repulsion
|
| 50 |
+
for j in range(i + 1, n):
|
| 51 |
+
vec = centers[i] - centers[j]
|
| 52 |
+
dist = np.linalg.norm(vec)
|
| 53 |
+
if 0 < dist < repulsion_threshold:
|
| 54 |
+
force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist
|
| 55 |
+
force_vec = force_magnitude * (vec / dist)
|
| 56 |
+
forces[i] += force_vec
|
| 57 |
+
forces[j] -= force_vec
|
| 58 |
+
# Boundary repulsion
|
| 59 |
+
x, y = centers[i]
|
| 60 |
+
if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x)
|
| 61 |
+
if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin))
|
| 62 |
+
if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y)
|
| 63 |
+
if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin))
|
| 64 |
+
centers += step_size * forces
|
| 65 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 66 |
+
return centers
|
| 67 |
+
|
| 68 |
+
def construct_packing():
|
| 69 |
+
"""
|
| 70 |
+
Constructs a high-density arrangement of 26 circles. This method combines
|
| 71 |
+
a proven asymmetric initialization, a mild force-directed pre-relaxation,
|
| 72 |
+
and a sophisticated Simulated Annealing local search with adaptive heuristics.
|
| 73 |
+
"""
|
| 74 |
+
n = 26
|
| 75 |
+
|
| 76 |
+
# 1. Initialization: Asymmetric Gaussian-deformed grid.
|
| 77 |
+
x_coords = np.linspace(0.1, 0.9, 5)
|
| 78 |
+
y_coords = np.linspace(0.1, 0.9, 5)
|
| 79 |
+
xx, yy = np.meshgrid(x_coords, y_coords)
|
| 80 |
+
base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T
|
| 81 |
+
void_center = np.array([0.4, 0.2])
|
| 82 |
+
amplitude, sigma = 0.06, 0.15
|
| 83 |
+
|
| 84 |
+
displacements = base_centers_25 - void_center
|
| 85 |
+
distances = np.linalg.norm(displacements, axis=1)
|
| 86 |
+
mask = distances > 1e-9
|
| 87 |
+
push_magnitudes = np.zeros(25)
|
| 88 |
+
push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2))
|
| 89 |
+
displacements[mask] /= distances[mask, np.newaxis]
|
| 90 |
+
|
| 91 |
+
centers = np.zeros((n, 2))
|
| 92 |
+
centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis]
|
| 93 |
+
centers[25] = void_center
|
| 94 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 95 |
+
|
| 96 |
+
# 2. Pre-optimization: A mild force-directed relaxation to settle the initial state.
|
| 97 |
+
centers = apply_force_directed_relaxation(
|
| 98 |
+
centers, iterations=500, step_size=0.001, repulsion_strength=0.01,
|
| 99 |
+
repulsion_threshold=0.18, boundary_strength=0.05, boundary_margin=0.03
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
# 3. Main Optimization: Advanced Simulated Annealing with Stagnation Escape.
|
| 103 |
+
radii = compute_max_radii(centers)
|
| 104 |
+
|
| 105 |
+
best_centers = centers.copy()
|
| 106 |
+
best_radii = radii.copy()
|
| 107 |
+
best_sum_radii = np.sum(radii)
|
| 108 |
+
|
| 109 |
+
current_centers = centers.copy()
|
| 110 |
+
current_radii = radii.copy()
|
| 111 |
+
current_sum_radii = best_sum_radii
|
| 112 |
+
|
| 113 |
+
# Tuned SA parameters based on high-performing ancestors for better exploration
|
| 114 |
+
total_iterations = 15000
|
| 115 |
+
initial_g_perturb_base = 0.04
|
| 116 |
+
final_g_perturb = 0.0003
|
| 117 |
+
T_initial, T_final = 0.2, 1e-7
|
| 118 |
+
|
| 119 |
+
# Stagnation escape mechanism to kick search out of local optima
|
| 120 |
+
no_improvement_count = 0
|
| 121 |
+
max_no_improvement_steps = 500
|
| 122 |
+
current_initial_g_perturb = initial_g_perturb_base
|
| 123 |
+
|
| 124 |
+
for it in range(total_iterations):
|
| 125 |
+
# Annealing schedules with dynamic perturbation
|
| 126 |
+
g_perturb = current_initial_g_perturb + (final_g_perturb - current_initial_g_perturb) * (it / total_iterations)
|
| 127 |
+
temp = T_initial * (T_final / T_initial)**(it / total_iterations)
|
| 128 |
+
|
| 129 |
+
candidate_centers = current_centers.copy()
|
| 130 |
+
|
| 131 |
+
# Adaptive Selection: Prioritize small circles and those near boundaries
|
| 132 |
+
inverse_radii = 1 / (current_radii + 1e-8)
|
| 133 |
+
dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0)
|
| 134 |
+
boundary_weight = np.exp(-dist_to_boundary / 0.1)
|
| 135 |
+
weights = inverse_radii * (1 + boundary_weight)
|
| 136 |
+
probs = weights / np.sum(weights)
|
| 137 |
+
circle_idx = np.random.choice(n, p=probs)
|
| 138 |
+
|
| 139 |
+
# Adaptive Perturbation: Give larger kicks to smaller circles
|
| 140 |
+
max_r = np.max(current_radii) + 1e-8
|
| 141 |
+
relative_r = current_radii[circle_idx] / max_r
|
| 142 |
+
# Increased multiplier for more aggressive small circle movement
|
| 143 |
+
perturb_factor = 1.0 + (1.0 - relative_r) * 2.0
|
| 144 |
+
eff_perturb = g_perturb * perturb_factor
|
| 145 |
+
|
| 146 |
+
displacement = np.random.uniform(-eff_perturb, eff_perturb, 2)
|
| 147 |
+
candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0)
|
| 148 |
+
|
| 149 |
+
# Evaluation and Acceptance
|
| 150 |
+
candidate_radii = compute_max_radii(candidate_centers)
|
| 151 |
+
candidate_sum_radii = np.sum(candidate_radii)
|
| 152 |
+
|
| 153 |
+
accepted = False
|
| 154 |
+
delta = candidate_sum_radii - current_sum_radii
|
| 155 |
+
if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)):
|
| 156 |
+
current_sum_radii = candidate_sum_radii
|
| 157 |
+
current_centers = candidate_centers.copy()
|
| 158 |
+
current_radii = candidate_radii.copy()
|
| 159 |
+
accepted = True
|
| 160 |
+
|
| 161 |
+
# Update best solution and manage stagnation
|
| 162 |
+
if current_sum_radii > best_sum_radii:
|
| 163 |
+
best_sum_radii = current_sum_radii
|
| 164 |
+
best_centers = current_centers.copy()
|
| 165 |
+
best_radii = current_radii.copy()
|
| 166 |
+
no_improvement_count = 0 # Reset on new best
|
| 167 |
+
elif not accepted:
|
| 168 |
+
no_improvement_count += 1
|
| 169 |
+
# If stagnated, boost perturbation to escape local optimum
|
| 170 |
+
if no_improvement_count > max_no_improvement_steps:
|
| 171 |
+
current_initial_g_perturb *= 1.2
|
| 172 |
+
no_improvement_count = 0
|
| 173 |
+
|
| 174 |
+
return best_centers, best_radii
|
| 175 |
+
# EVOLVE-BLOCK-END
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
# This part remains fixed (not evolved)
|
| 179 |
+
def run_packing():
|
| 180 |
+
"""Run the circle packing constructor for n=26"""
|
| 181 |
+
centers, radii = construct_packing()
|
| 182 |
+
# Calculate the sum of radii
|
| 183 |
+
sum_radii = np.sum(radii)
|
| 184 |
+
return centers, radii, sum_radii
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/correct.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"correct": true,
|
| 3 |
+
"error": null
|
| 4 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/job_log.err
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning:
|
| 2 |
+
|
| 3 |
+
All support for the `google.generativeai` package has ended. It will no longer be receiving
|
| 4 |
+
updates or bug fixes. Please switch to the `google.genai` package as soon as possible.
|
| 5 |
+
See README for more details:
|
| 6 |
+
|
| 7 |
+
https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md
|
| 8 |
+
|
| 9 |
+
import google.generativeai as genai # type: ignore[import-not-found]
|
| 10 |
+
/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/main.py:81: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None.
|
| 11 |
+
normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0)
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/job_log.out
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/main.py
|
| 2 |
+
Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/results
|
| 3 |
+
Run 1/1 completed in 87.47 seconds
|
| 4 |
+
Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/results/extra.npz
|
| 5 |
+
Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/results/packing_viz.png
|
| 6 |
+
Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/results/correct.json
|
| 7 |
+
Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/results/metrics.json
|
| 8 |
+
Evaluation and Validation completed successfully.
|
| 9 |
+
Metrics:
|
| 10 |
+
combined_score: 2.454803266030448
|
| 11 |
+
public: {'centers_str': ' centers[0] = (0.0912, 0.0912)\n centers[1] = (0.9197, 0.9197)\n centers[2] = (0.6416, 0.5844)\n centers[3] = (0.7195, 0.1052)\n centers[4] = (0.2830, 0.5537)\n centers[5] = (0.0989, 0.2811)\n centers[6] = (0.3886, 0.2380)\n centers[7] = (0.6832, 0.2816)\n centers[8] = (0.5049, 0.3195)\n centers[9] = (0.8949, 0.3191)\n centers[10] = (0.0858, 0.4792)\n centers[11] = (0.8929, 0.1070)\n centers[12] = (0.5002, 0.5083)\n centers[13] = (0.7290, 0.4989)\n centers[14] = (0.6079, 0.7051)\n centers[15] = (0.9208, 0.5015)\n centers[16] = (0.5289, 0.1164)\n centers[17] = (0.3667, 0.7001)\n centers[18] = (0.2862, 0.4061)\n centers[19] = (0.8626, 0.7102)\n centers[20] = (0.0982, 0.9019)\n centers[21] = (0.2909, 0.9053)\n centers[22] = (0.4921, 0.8935)\n centers[23] = (0.7109, 0.8969)\n centers[24] = (0.2829, 0.1026)\n centers[25] = (0.1216, 0.6835)', 'num_circles': 26}
|
| 12 |
+
private: {'reported_sum_of_radii': 2.454803266030448}
|
| 13 |
+
visualization_path: <string_too_long_to_display>
|
| 14 |
+
execution_time_mean: 87.47112137591466
|
| 15 |
+
execution_time_std: 0.0
|
| 16 |
+
num_valid_runs: 1
|
| 17 |
+
num_invalid_runs: 0
|
| 18 |
+
all_validation_errors: []
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/metrics.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"combined_score": 2.454803266030448,
|
| 3 |
+
"public": {
|
| 4 |
+
"centers_str": " centers[0] = (0.0912, 0.0912)\n centers[1] = (0.9197, 0.9197)\n centers[2] = (0.6416, 0.5844)\n centers[3] = (0.7195, 0.1052)\n centers[4] = (0.2830, 0.5537)\n centers[5] = (0.0989, 0.2811)\n centers[6] = (0.3886, 0.2380)\n centers[7] = (0.6832, 0.2816)\n centers[8] = (0.5049, 0.3195)\n centers[9] = (0.8949, 0.3191)\n centers[10] = (0.0858, 0.4792)\n centers[11] = (0.8929, 0.1070)\n centers[12] = (0.5002, 0.5083)\n centers[13] = (0.7290, 0.4989)\n centers[14] = (0.6079, 0.7051)\n centers[15] = (0.9208, 0.5015)\n centers[16] = (0.5289, 0.1164)\n centers[17] = (0.3667, 0.7001)\n centers[18] = (0.2862, 0.4061)\n centers[19] = (0.8626, 0.7102)\n centers[20] = (0.0982, 0.9019)\n centers[21] = (0.2909, 0.9053)\n centers[22] = (0.4921, 0.8935)\n centers[23] = (0.7109, 0.8969)\n centers[24] = (0.2829, 0.1026)\n centers[25] = (0.1216, 0.6835)",
|
| 5 |
+
"num_circles": 26
|
| 6 |
+
},
|
| 7 |
+
"private": {
|
| 8 |
+
"reported_sum_of_radii": 2.454803266030448
|
| 9 |
+
},
|
| 10 |
+
"visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/results/packing_viz.png",
|
| 11 |
+
"execution_time_mean": 87.47112137591466,
|
| 12 |
+
"execution_time_std": 0.0,
|
| 13 |
+
"num_valid_runs": 1,
|
| 14 |
+
"num_invalid_runs": 0,
|
| 15 |
+
"all_validation_errors": []
|
| 16 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/rewrite.txt
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# EVOLVE-BLOCK-START
|
| 2 |
+
import numpy as np
|
| 3 |
+
import math
|
| 4 |
+
|
| 5 |
+
def compute_max_radii(centers, max_iterations=750):
|
| 6 |
+
"""
|
| 7 |
+
Compute the maximum possible radii for each circle position
|
| 8 |
+
such that they don't overlap and stay within the unit square. This is
|
| 9 |
+
an iterative version that converges to a stable solution.
|
| 10 |
+
"""
|
| 11 |
+
n = centers.shape[0]
|
| 12 |
+
radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0)
|
| 13 |
+
for _ in range(max_iterations):
|
| 14 |
+
changes_made = False
|
| 15 |
+
for i in range(n):
|
| 16 |
+
for j in range(i + 1, n):
|
| 17 |
+
dist = np.linalg.norm(centers[i] - centers[j])
|
| 18 |
+
if radii[i] + radii[j] > dist + 1e-12:
|
| 19 |
+
sum_r = radii[i] + radii[j]
|
| 20 |
+
if sum_r > 1e-12:
|
| 21 |
+
scale = dist / sum_r
|
| 22 |
+
ri_new, rj_new = radii[i] * scale, radii[j] * scale
|
| 23 |
+
if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12:
|
| 24 |
+
radii[i], radii[j] = ri_new, rj_new
|
| 25 |
+
changes_made = True
|
| 26 |
+
if not changes_made:
|
| 27 |
+
break
|
| 28 |
+
return radii
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class CirclePackingOrchestrator:
|
| 32 |
+
"""
|
| 33 |
+
Manages a multi-stage circle packing pipeline, structured for clarity and performance.
|
| 34 |
+
|
| 35 |
+
This orchestrator class encapsulates the entire process, from finding a promising
|
| 36 |
+
initial configuration via a multi-start strategy to refining it with an advanced
|
| 37 |
+
Simulated Annealing algorithm and final polishing. This structure separates concerns,
|
| 38 |
+
making the process more modular and maintainable.
|
| 39 |
+
"""
|
| 40 |
+
def __init__(self, n=26):
|
| 41 |
+
self.n = n
|
| 42 |
+
self.centers = np.zeros((n, 2))
|
| 43 |
+
self.best_centers = None
|
| 44 |
+
self.best_radii = None
|
| 45 |
+
self.best_sum_radii = -1.0
|
| 46 |
+
|
| 47 |
+
def _generate_void_config(self, void_center, amplitude, sigma):
|
| 48 |
+
"""Helper to generate initial centers from a grid deformed by a Gaussian push."""
|
| 49 |
+
x_coords = np.linspace(0.1, 0.9, 5)
|
| 50 |
+
y_coords = np.linspace(0.1, 0.9, 5)
|
| 51 |
+
xx, yy = np.meshgrid(x_coords, y_coords)
|
| 52 |
+
base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T
|
| 53 |
+
|
| 54 |
+
displacements = base_centers_25 - void_center
|
| 55 |
+
distances = np.linalg.norm(displacements, axis=1)
|
| 56 |
+
mask = distances > 1e-9
|
| 57 |
+
|
| 58 |
+
push_magnitudes = np.zeros(25)
|
| 59 |
+
if np.any(mask):
|
| 60 |
+
push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2))
|
| 61 |
+
displacements[mask] /= distances[mask, np.newaxis]
|
| 62 |
+
|
| 63 |
+
initial_centers = np.zeros((self.n, 2))
|
| 64 |
+
initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis]
|
| 65 |
+
initial_centers[25] = void_center
|
| 66 |
+
return np.clip(initial_centers, 0.0, 1.0)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin):
|
| 70 |
+
"""Performs a vectorized force-directed relaxation phase for speed."""
|
| 71 |
+
for _ in range(iters):
|
| 72 |
+
diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :]
|
| 73 |
+
dists = np.linalg.norm(diff, axis=2)
|
| 74 |
+
np.fill_diagonal(dists, np.inf)
|
| 75 |
+
|
| 76 |
+
repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9)
|
| 77 |
+
|
| 78 |
+
force_magnitudes = np.zeros_like(dists)
|
| 79 |
+
force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask]
|
| 80 |
+
|
| 81 |
+
normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0)
|
| 82 |
+
forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1)
|
| 83 |
+
|
| 84 |
+
forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0])
|
| 85 |
+
forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin))
|
| 86 |
+
forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1])
|
| 87 |
+
forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin))
|
| 88 |
+
|
| 89 |
+
self.centers += step_size * forces
|
| 90 |
+
self.centers = np.clip(self.centers, 0.0, 1.0)
|
| 91 |
+
|
| 92 |
+
def _initialize_and_select_best_start(self, num_starts=8):
|
| 93 |
+
"""
|
| 94 |
+
Runs a multi-start initialization. Generates several random starting
|
| 95 |
+
configurations, performs a quick relaxation on each, and selects the
|
| 96 |
+
best one to seed the main SA optimization.
|
| 97 |
+
"""
|
| 98 |
+
best_start_score = -1.0
|
| 99 |
+
best_start_centers = None
|
| 100 |
+
|
| 101 |
+
for _ in range(num_starts):
|
| 102 |
+
void_center = np.random.uniform(0.2, 0.8, 2)
|
| 103 |
+
amplitude = np.random.uniform(0.05, 0.1)
|
| 104 |
+
sigma = np.random.uniform(0.1, 0.2)
|
| 105 |
+
self.centers = self._generate_void_config(void_center, amplitude, sigma)
|
| 106 |
+
|
| 107 |
+
self._force_directed_relaxation_vectorized(
|
| 108 |
+
iters=300, step_size=0.002, repulsion_strength=0.02,
|
| 109 |
+
boundary_strength=0.08, repulsion_threshold=0.2, boundary_margin=0.04
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
radii = compute_max_radii(self.centers, max_iterations=100)
|
| 113 |
+
score = np.sum(radii)
|
| 114 |
+
|
| 115 |
+
if score > best_start_score:
|
| 116 |
+
best_start_score = score
|
| 117 |
+
best_start_centers = self.centers.copy()
|
| 118 |
+
|
| 119 |
+
self.centers = best_start_centers
|
| 120 |
+
self.best_centers = best_start_centers.copy()
|
| 121 |
+
self.best_radii = compute_max_radii(self.best_centers)
|
| 122 |
+
self.best_sum_radii = np.sum(self.best_radii)
|
| 123 |
+
|
| 124 |
+
def _select_circle_context_aware(self, current_radii, current_centers):
|
| 125 |
+
"""Intelligently selects a circle to perturb."""
|
| 126 |
+
inverse_radii = 1 / (current_radii + 1e-8)
|
| 127 |
+
dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0],
|
| 128 |
+
current_centers[:, 1], 1 - current_centers[:, 1]], axis=0)
|
| 129 |
+
boundary_weight = np.exp(-dist_to_boundary / 0.08)
|
| 130 |
+
combined_weights = inverse_radii * (1 + boundary_weight)
|
| 131 |
+
selection_probs = combined_weights / np.sum(combined_weights)
|
| 132 |
+
return np.random.choice(self.n, p=selection_probs)
|
| 133 |
+
|
| 134 |
+
def _simulated_annealing_search(self):
|
| 135 |
+
"""
|
| 136 |
+
Performs the main optimization using SA with multi-modal perturbations,
|
| 137 |
+
adaptive parameters, and a refined stagnation escape mechanism.
|
| 138 |
+
"""
|
| 139 |
+
total_iterations = 40000
|
| 140 |
+
initial_temp, final_temp = 0.001, 1e-10
|
| 141 |
+
initial_perturb_strength, final_perturb_strength = 0.04, 0.0001
|
| 142 |
+
|
| 143 |
+
current_centers = self.centers.copy()
|
| 144 |
+
current_radii = self.best_radii.copy()
|
| 145 |
+
current_sum_radii = self.best_sum_radii
|
| 146 |
+
|
| 147 |
+
swap_prob, cluster_prob = 0.10, 0.15
|
| 148 |
+
|
| 149 |
+
stagnation_counter, stagnation_threshold = 0, 1500
|
| 150 |
+
perturb_boost, boost_factor, boost_decay = 1.0, 4.0, 0.97
|
| 151 |
+
temp_reheat_factor = 0.5
|
| 152 |
+
|
| 153 |
+
min_radii_iters, max_radii_iters = 150, 800
|
| 154 |
+
|
| 155 |
+
for iteration in range(total_iterations):
|
| 156 |
+
progress = iteration / total_iterations
|
| 157 |
+
temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress)
|
| 158 |
+
base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress)
|
| 159 |
+
radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress)
|
| 160 |
+
|
| 161 |
+
current_temp = temp_schedule
|
| 162 |
+
if stagnation_counter >= stagnation_threshold:
|
| 163 |
+
perturb_boost = boost_factor
|
| 164 |
+
current_temp += initial_temp * temp_reheat_factor
|
| 165 |
+
stagnation_counter = 0
|
| 166 |
+
|
| 167 |
+
candidate_centers = current_centers.copy()
|
| 168 |
+
rand_val = np.random.rand()
|
| 169 |
+
|
| 170 |
+
if rand_val < swap_prob:
|
| 171 |
+
if self.n > 1:
|
| 172 |
+
sorted_indices = np.argsort(current_radii)
|
| 173 |
+
num_candidates = max(1, self.n // 4)
|
| 174 |
+
idx_small = np.random.choice(sorted_indices[:num_candidates])
|
| 175 |
+
idx_large = np.random.choice(sorted_indices[-num_candidates:])
|
| 176 |
+
if idx_small != idx_large:
|
| 177 |
+
candidate_centers[idx_small], candidate_centers[idx_large] = \
|
| 178 |
+
candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy()
|
| 179 |
+
|
| 180 |
+
elif rand_val < swap_prob + cluster_prob:
|
| 181 |
+
primary_idx = self._select_circle_context_aware(current_radii, current_centers)
|
| 182 |
+
distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1)
|
| 183 |
+
distances[primary_idx] = np.inf
|
| 184 |
+
neighbor_indices = np.argsort(distances)[:2]
|
| 185 |
+
indices_to_perturb = np.append(neighbor_indices, primary_idx)
|
| 186 |
+
|
| 187 |
+
eff_strength = base_perturb_strength * perturb_boost * 0.6
|
| 188 |
+
displacement = np.random.uniform(-eff_strength, eff_strength, 2)
|
| 189 |
+
candidate_centers[indices_to_perturb] += displacement
|
| 190 |
+
|
| 191 |
+
else:
|
| 192 |
+
circle_idx = self._select_circle_context_aware(current_radii, current_centers)
|
| 193 |
+
max_r = np.max(current_radii) + 1e-8
|
| 194 |
+
relative_radius = current_radii[circle_idx] / max_r
|
| 195 |
+
perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5
|
| 196 |
+
eff_strength = base_perturb_strength * perturb_factor * perturb_boost
|
| 197 |
+
displacement = np.random.uniform(-eff_strength, eff_strength, 2)
|
| 198 |
+
candidate_centers[circle_idx] += displacement
|
| 199 |
+
|
| 200 |
+
candidate_centers = np.clip(candidate_centers, 0.0, 1.0)
|
| 201 |
+
if perturb_boost > 1.0:
|
| 202 |
+
perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay
|
| 203 |
+
|
| 204 |
+
candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit)
|
| 205 |
+
candidate_sum_radii = np.sum(candidate_radii)
|
| 206 |
+
|
| 207 |
+
delta_E = candidate_sum_radii - current_sum_radii
|
| 208 |
+
if delta_E > 0 or (current_temp > 1e-12 and np.random.rand() < math.exp(delta_E / current_temp)):
|
| 209 |
+
current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii
|
| 210 |
+
if current_sum_radii > self.best_sum_radii:
|
| 211 |
+
self.best_sum_radii = current_sum_radii
|
| 212 |
+
self.best_centers = current_centers.copy()
|
| 213 |
+
self.best_radii = current_radii.copy()
|
| 214 |
+
stagnation_counter = 0
|
| 215 |
+
else:
|
| 216 |
+
stagnation_counter += 1
|
| 217 |
+
else:
|
| 218 |
+
stagnation_counter += 1
|
| 219 |
+
|
| 220 |
+
self.centers = self.best_centers.copy()
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
def pack(self):
|
| 224 |
+
"""Executes the full, orchestrated packing pipeline."""
|
| 225 |
+
self._initialize_and_select_best_start(num_starts=8)
|
| 226 |
+
|
| 227 |
+
self._simulated_annealing_search()
|
| 228 |
+
|
| 229 |
+
self.centers = self.best_centers.copy()
|
| 230 |
+
self._force_directed_relaxation_vectorized(
|
| 231 |
+
iters=500, step_size=0.0001, repulsion_strength=0.001,
|
| 232 |
+
boundary_strength=0.01, repulsion_threshold=0.18, boundary_margin=0.02
|
| 233 |
+
)
|
| 234 |
+
|
| 235 |
+
final_radii = compute_max_radii(self.centers, max_iterations=1000)
|
| 236 |
+
final_sum_radii = np.sum(final_radii)
|
| 237 |
+
|
| 238 |
+
if final_sum_radii > self.best_sum_radii:
|
| 239 |
+
self.best_radii = final_radii
|
| 240 |
+
self.best_centers = self.centers
|
| 241 |
+
|
| 242 |
+
return self.best_centers, self.best_radii
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
def construct_packing():
|
| 246 |
+
"""
|
| 247 |
+
Constructs a high-density arrangement of 26 circles by instantiating and
|
| 248 |
+
running the CirclePackingOrchestrator.
|
| 249 |
+
"""
|
| 250 |
+
orchestrator = CirclePackingOrchestrator(n=26)
|
| 251 |
+
centers, radii = orchestrator.pack()
|
| 252 |
+
return centers, radii
|
| 253 |
+
# EVOLVE-BLOCK-END
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/__pycache__/main.cpython-311.pyc
ADDED
|
Binary file (3.43 kB). View file
|
|
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/correct.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"correct": true,
|
| 3 |
+
"error": null
|
| 4 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/job_log.err
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning:
|
| 2 |
+
|
| 3 |
+
All support for the `google.generativeai` package has ended. It will no longer be receiving
|
| 4 |
+
updates or bug fixes. Please switch to the `google.genai` package as soon as possible.
|
| 5 |
+
See README for more details:
|
| 6 |
+
|
| 7 |
+
https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md
|
| 8 |
+
|
| 9 |
+
import google.generativeai as genai # type: ignore[import-not-found]
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/job_log.out
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/main.py
|
| 2 |
+
Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/results
|
| 3 |
+
Run 1/1 completed in 0.00 seconds
|
| 4 |
+
Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/extra.npz
|
| 5 |
+
Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/packing_viz.png
|
| 6 |
+
Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/correct.json
|
| 7 |
+
Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/metrics.json
|
| 8 |
+
Evaluation and Validation completed successfully.
|
| 9 |
+
Metrics:
|
| 10 |
+
combined_score: 0.9597642169962064
|
| 11 |
+
public: {'centers_str': ' centers[0] = (0.5000, 0.5000)\n centers[1] = (0.8000, 0.5000)\n centers[2] = (0.7121, 0.7121)\n centers[3] = (0.5000, 0.8000)\n centers[4] = (0.2879, 0.7121)\n centers[5] = (0.2000, 0.5000)\n centers[6] = (0.2879, 0.2879)\n centers[7] = (0.5000, 0.2000)\n centers[8] = (0.7121, 0.2879)\n centers[9] = (0.9900, 0.5000)\n centers[10] = (0.9900, 0.7679)\n centers[11] = (0.9900, 0.9900)\n centers[12] = (0.7679, 0.9900)\n centers[13] = (0.5000, 0.9900)\n centers[14] = (0.2321, 0.9900)\n centers[15] = (0.0100, 0.9900)\n centers[16] = (0.0100, 0.7679)\n centers[17] = (0.0100, 0.5000)\n centers[18] = (0.0100, 0.2321)\n centers[19] = (0.0100, 0.0100)\n centers[20] = (0.2321, 0.0100)\n centers[21] = (0.5000, 0.0100)\n centers[22] = (0.7679, 0.0100)\n centers[23] = (0.9900, 0.0100)\n centers[24] = (0.9900, 0.2321)\n centers[25] = (0.0100, 0.0100)', 'num_circles': 26}
|
| 12 |
+
private: {'reported_sum_of_radii': 0.9597642169962064}
|
| 13 |
+
visualization_path: <string_too_long_to_display>
|
| 14 |
+
execution_time_mean: 0.002032745163887739
|
| 15 |
+
execution_time_std: 0.0
|
| 16 |
+
num_valid_runs: 1
|
| 17 |
+
num_invalid_runs: 0
|
| 18 |
+
all_validation_errors: []
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/metrics.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"combined_score": 0.9597642169962064,
|
| 3 |
+
"public": {
|
| 4 |
+
"centers_str": " centers[0] = (0.5000, 0.5000)\n centers[1] = (0.8000, 0.5000)\n centers[2] = (0.7121, 0.7121)\n centers[3] = (0.5000, 0.8000)\n centers[4] = (0.2879, 0.7121)\n centers[5] = (0.2000, 0.5000)\n centers[6] = (0.2879, 0.2879)\n centers[7] = (0.5000, 0.2000)\n centers[8] = (0.7121, 0.2879)\n centers[9] = (0.9900, 0.5000)\n centers[10] = (0.9900, 0.7679)\n centers[11] = (0.9900, 0.9900)\n centers[12] = (0.7679, 0.9900)\n centers[13] = (0.5000, 0.9900)\n centers[14] = (0.2321, 0.9900)\n centers[15] = (0.0100, 0.9900)\n centers[16] = (0.0100, 0.7679)\n centers[17] = (0.0100, 0.5000)\n centers[18] = (0.0100, 0.2321)\n centers[19] = (0.0100, 0.0100)\n centers[20] = (0.2321, 0.0100)\n centers[21] = (0.5000, 0.0100)\n centers[22] = (0.7679, 0.0100)\n centers[23] = (0.9900, 0.0100)\n centers[24] = (0.9900, 0.2321)\n centers[25] = (0.0100, 0.0100)",
|
| 5 |
+
"num_circles": 26
|
| 6 |
+
},
|
| 7 |
+
"private": {
|
| 8 |
+
"reported_sum_of_radii": 0.9597642169962064
|
| 9 |
+
},
|
| 10 |
+
"visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/packing_viz.png",
|
| 11 |
+
"execution_time_mean": 0.002032745163887739,
|
| 12 |
+
"execution_time_std": 0.0,
|
| 13 |
+
"num_valid_runs": 1,
|
| 14 |
+
"num_invalid_runs": 0,
|
| 15 |
+
"all_validation_errors": []
|
| 16 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/__pycache__/main.cpython-311.pyc
ADDED
|
Binary file (3.24 kB). View file
|
|
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/correct.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"correct": true,
|
| 3 |
+
"error": null
|
| 4 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/job_log.err
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning:
|
| 2 |
+
|
| 3 |
+
All support for the `google.generativeai` package has ended. It will no longer be receiving
|
| 4 |
+
updates or bug fixes. Please switch to the `google.genai` package as soon as possible.
|
| 5 |
+
See README for more details:
|
| 6 |
+
|
| 7 |
+
https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md
|
| 8 |
+
|
| 9 |
+
import google.generativeai as genai # type: ignore[import-not-found]
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/job_log.out
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/main.py
|
| 2 |
+
Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/results
|
| 3 |
+
Run 1/1 completed in 0.00 seconds
|
| 4 |
+
Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/extra.npz
|
| 5 |
+
Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/packing_viz.png
|
| 6 |
+
Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/correct.json
|
| 7 |
+
Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/metrics.json
|
| 8 |
+
Evaluation and Validation completed successfully.
|
| 9 |
+
Metrics:
|
| 10 |
+
combined_score: 1.7873680766471653
|
| 11 |
+
public: {'centers_str': ' centers[0] = (0.1000, 0.1000)\n centers[1] = (0.3000, 0.1000)\n centers[2] = (0.5000, 0.1000)\n centers[3] = (0.7000, 0.1000)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.1000, 0.3000)\n centers[6] = (0.3000, 0.3000)\n centers[7] = (0.5000, 0.3000)\n centers[8] = (0.7000, 0.3000)\n centers[9] = (0.9000, 0.3000)\n centers[10] = (0.1000, 0.5000)\n centers[11] = (0.3000, 0.5000)\n centers[12] = (0.5000, 0.5000)\n centers[13] = (0.7000, 0.5000)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7000)\n centers[17] = (0.5000, 0.7000)\n centers[18] = (0.7000, 0.7000)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1000, 0.9000)\n centers[21] = (0.3000, 0.9000)\n centers[22] = (0.5000, 0.9000)\n centers[23] = (0.7000, 0.9000)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.5000, 0.5000)', 'num_circles': 26}
|
| 12 |
+
private: {'reported_sum_of_radii': 1.7873680766471653}
|
| 13 |
+
visualization_path: <string_too_long_to_display>
|
| 14 |
+
execution_time_mean: 0.002029381226748228
|
| 15 |
+
execution_time_std: 0.0
|
| 16 |
+
num_valid_runs: 1
|
| 17 |
+
num_invalid_runs: 0
|
| 18 |
+
all_validation_errors: []
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/metrics.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"combined_score": 1.7873680766471653,
|
| 3 |
+
"public": {
|
| 4 |
+
"centers_str": " centers[0] = (0.1000, 0.1000)\n centers[1] = (0.3000, 0.1000)\n centers[2] = (0.5000, 0.1000)\n centers[3] = (0.7000, 0.1000)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.1000, 0.3000)\n centers[6] = (0.3000, 0.3000)\n centers[7] = (0.5000, 0.3000)\n centers[8] = (0.7000, 0.3000)\n centers[9] = (0.9000, 0.3000)\n centers[10] = (0.1000, 0.5000)\n centers[11] = (0.3000, 0.5000)\n centers[12] = (0.5000, 0.5000)\n centers[13] = (0.7000, 0.5000)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7000)\n centers[17] = (0.5000, 0.7000)\n centers[18] = (0.7000, 0.7000)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1000, 0.9000)\n centers[21] = (0.3000, 0.9000)\n centers[22] = (0.5000, 0.9000)\n centers[23] = (0.7000, 0.9000)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.5000, 0.5000)",
|
| 5 |
+
"num_circles": 26
|
| 6 |
+
},
|
| 7 |
+
"private": {
|
| 8 |
+
"reported_sum_of_radii": 1.7873680766471653
|
| 9 |
+
},
|
| 10 |
+
"visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/packing_viz.png",
|
| 11 |
+
"execution_time_mean": 0.002029381226748228,
|
| 12 |
+
"execution_time_std": 0.0,
|
| 13 |
+
"num_valid_runs": 1,
|
| 14 |
+
"num_invalid_runs": 0,
|
| 15 |
+
"all_validation_errors": []
|
| 16 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/__pycache__/main.cpython-311.pyc
ADDED
|
Binary file (3.22 kB). View file
|
|
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/edit.diff
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
--- a/original.py
|
| 2 |
+
+++ b/original.py
|
| 3 |
+
@@ -1,94 +1,106 @@
|
| 4 |
+
# EVOLVE-BLOCK-START
|
| 5 |
+
"""Constructor-based circle packing for n=26 circles"""
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def construct_packing():
|
| 11 |
+
"""
|
| 12 |
+
Construct a specific arrangement of 26 circles in a unit square
|
| 13 |
+
that attempts to maximize the sum of their radii.
|
| 14 |
+
|
| 15 |
+
Returns:
|
| 16 |
+
Tuple of (centers, radii, sum_of_radii)
|
| 17 |
+
centers: np.array of shape (26, 2) with (x, y) coordinates
|
| 18 |
+
radii: np.array of shape (26) with radius of each circle
|
| 19 |
+
sum_of_radii: Sum of all radii
|
| 20 |
+
"""
|
| 21 |
+
# Initialize arrays for 26 circles
|
| 22 |
+
n = 26
|
| 23 |
+
centers = np.zeros((n, 2))
|
| 24 |
+
|
| 25 |
+
- # Place circles in a structured pattern
|
| 26 |
+
- # This is a simple pattern - evolution will improve this
|
| 27 |
+
+ # Using a 5-5-6-5-5 column-like structure.
|
| 28 |
+
+ # This structure is inspired by known good packings for N=26 and provides
|
| 29 |
+
+ # much better space utilization than the previous concentric ring model.
|
| 30 |
+
+ # It avoids the need for clipping, which created tiny, inefficient circles.
|
| 31 |
+
|
| 32 |
+
- # First, place a large circle in the center
|
| 33 |
+
- centers[0] = [0.5, 0.5]
|
| 34 |
+
+ # x-coordinates for the 5 columns
|
| 35 |
+
+ x_cols = np.linspace(0.1, 0.9, 5)
|
| 36 |
+
|
| 37 |
+
- # Place 8 circles around it in a ring
|
| 38 |
+
- for i in range(8):
|
| 39 |
+
- angle = 2 * np.pi * i / 8
|
| 40 |
+
- centers[i + 1] = [0.5 + 0.22 * np.cos(angle), 0.5 + 0.22 * np.sin(angle)]
|
| 41 |
+
+ # y-coordinates for columns with 5 circles
|
| 42 |
+
+ y_5 = np.linspace(0.1, 0.9, 5)
|
| 43 |
+
|
| 44 |
+
- # Place 16 more circles in an outer ring
|
| 45 |
+
- for i in range(16):
|
| 46 |
+
- angle = 2 * np.pi * i / 16
|
| 47 |
+
- centers[i + 9] = [0.5 + 0.41 * np.cos(angle), 0.5 + 0.41 * np.sin(angle)]
|
| 48 |
+
+ # y-coordinates for the central column with 6 circles
|
| 49 |
+
+ y_6 = np.linspace(1/12, 11/12, 6)
|
| 50 |
+
|
| 51 |
+
- # Additional positioning adjustment to make sure all circles
|
| 52 |
+
- # are inside the square and don't overlap
|
| 53 |
+
- # Clip to ensure everything is inside the unit square
|
| 54 |
+
- centers = np.clip(centers, 0.01, 0.99)
|
| 55 |
+
+ count = 0
|
| 56 |
+
+ # Arrange circles column by column
|
| 57 |
+
+ for i in range(5):
|
| 58 |
+
+ x = x_cols[i]
|
| 59 |
+
+
|
| 60 |
+
+ # The central column (i=2) has 6 circles
|
| 61 |
+
+ if i == 2:
|
| 62 |
+
+ for y in y_6:
|
| 63 |
+
+ centers[count] = [x, y]
|
| 64 |
+
+ count += 1
|
| 65 |
+
+ # The other four columns have 5 circles each
|
| 66 |
+
+ else:
|
| 67 |
+
+ for y in y_5:
|
| 68 |
+
+ centers[count] = [x, y]
|
| 69 |
+
+ count += 1
|
| 70 |
+
+
|
| 71 |
+
+ # This construction places all centers within the (0,1) square,
|
| 72 |
+
+ # so no clipping is necessary.
|
| 73 |
+
|
| 74 |
+
# Compute maximum valid radii for this configuration
|
| 75 |
+
radii = compute_max_radii(centers)
|
| 76 |
+
return centers, radii
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def compute_max_radii(centers):
|
| 80 |
+
"""
|
| 81 |
+
Compute the maximum possible radii for each circle position
|
| 82 |
+
such that they don't overlap and stay within the unit square.
|
| 83 |
+
|
| 84 |
+
Args:
|
| 85 |
+
centers: np.array of shape (n, 2) with (x, y) coordinates
|
| 86 |
+
|
| 87 |
+
Returns:
|
| 88 |
+
np.array of shape (n) with radius of each circle
|
| 89 |
+
"""
|
| 90 |
+
n = centers.shape[0]
|
| 91 |
+
radii = np.ones(n)
|
| 92 |
+
|
| 93 |
+
# First, limit by distance to square borders
|
| 94 |
+
for i in range(n):
|
| 95 |
+
x, y = centers[i]
|
| 96 |
+
# Distance to borders
|
| 97 |
+
radii[i] = min(x, y, 1 - x, 1 - y)
|
| 98 |
+
|
| 99 |
+
# Then, limit by distance to other circles
|
| 100 |
+
# Each pair of circles with centers at distance d can have
|
| 101 |
+
# sum of radii at most d to avoid overlap
|
| 102 |
+
for i in range(n):
|
| 103 |
+
for j in range(i + 1, n):
|
| 104 |
+
dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2))
|
| 105 |
+
|
| 106 |
+
# If current radii would cause overlap
|
| 107 |
+
if radii[i] + radii[j] > dist:
|
| 108 |
+
# Scale both radii proportionally
|
| 109 |
+
scale = dist / (radii[i] + radii[j])
|
| 110 |
+
radii[i] *= scale
|
| 111 |
+
radii[j] *= scale
|
| 112 |
+
|
| 113 |
+
return radii
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
# EVOLVE-BLOCK-END
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
# This part remains fixed (not evolved)
|
| 120 |
+
def run_packing():
|
| 121 |
+
"""Run the circle packing constructor for n=26"""
|
| 122 |
+
centers, radii = construct_packing()
|
| 123 |
+
# Calculate the sum of radii
|
| 124 |
+
sum_radii = np.sum(radii)
|
| 125 |
+
return centers, radii, sum_radii
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/main.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# EVOLVE-BLOCK-START
|
| 2 |
+
"""Constructor-based circle packing for n=26 circles"""
|
| 3 |
+
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def construct_packing():
|
| 8 |
+
"""
|
| 9 |
+
Construct a specific arrangement of 26 circles in a unit square
|
| 10 |
+
that attempts to maximize the sum of their radii.
|
| 11 |
+
|
| 12 |
+
Returns:
|
| 13 |
+
Tuple of (centers, radii, sum_of_radii)
|
| 14 |
+
centers: np.array of shape (26, 2) with (x, y) coordinates
|
| 15 |
+
radii: np.array of shape (26) with radius of each circle
|
| 16 |
+
sum_of_radii: Sum of all radii
|
| 17 |
+
"""
|
| 18 |
+
# Initialize arrays for 26 circles
|
| 19 |
+
n = 26
|
| 20 |
+
centers = np.zeros((n, 2))
|
| 21 |
+
|
| 22 |
+
# Using a 5-5-6-5-5 column-like structure.
|
| 23 |
+
# This structure is inspired by known good packings for N=26 and provides
|
| 24 |
+
# much better space utilization than the previous concentric ring model.
|
| 25 |
+
# It avoids the need for clipping, which created tiny, inefficient circles.
|
| 26 |
+
|
| 27 |
+
# x-coordinates for the 5 columns
|
| 28 |
+
x_cols = np.linspace(0.1, 0.9, 5)
|
| 29 |
+
|
| 30 |
+
# y-coordinates for columns with 5 circles
|
| 31 |
+
y_5 = np.linspace(0.1, 0.9, 5)
|
| 32 |
+
|
| 33 |
+
# y-coordinates for the central column with 6 circles
|
| 34 |
+
y_6 = np.linspace(1/12, 11/12, 6)
|
| 35 |
+
|
| 36 |
+
count = 0
|
| 37 |
+
# Arrange circles column by column
|
| 38 |
+
for i in range(5):
|
| 39 |
+
x = x_cols[i]
|
| 40 |
+
|
| 41 |
+
# The central column (i=2) has 6 circles
|
| 42 |
+
if i == 2:
|
| 43 |
+
for y in y_6:
|
| 44 |
+
centers[count] = [x, y]
|
| 45 |
+
count += 1
|
| 46 |
+
# The other four columns have 5 circles each
|
| 47 |
+
else:
|
| 48 |
+
for y in y_5:
|
| 49 |
+
centers[count] = [x, y]
|
| 50 |
+
count += 1
|
| 51 |
+
|
| 52 |
+
# This construction places all centers within the (0,1) square,
|
| 53 |
+
# so no clipping is necessary.
|
| 54 |
+
|
| 55 |
+
# Compute maximum valid radii for this configuration
|
| 56 |
+
radii = compute_max_radii(centers)
|
| 57 |
+
return centers, radii
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def compute_max_radii(centers):
|
| 61 |
+
"""
|
| 62 |
+
Compute the maximum possible radii for each circle position
|
| 63 |
+
such that they don't overlap and stay within the unit square.
|
| 64 |
+
|
| 65 |
+
Args:
|
| 66 |
+
centers: np.array of shape (n, 2) with (x, y) coordinates
|
| 67 |
+
|
| 68 |
+
Returns:
|
| 69 |
+
np.array of shape (n) with radius of each circle
|
| 70 |
+
"""
|
| 71 |
+
n = centers.shape[0]
|
| 72 |
+
radii = np.ones(n)
|
| 73 |
+
|
| 74 |
+
# First, limit by distance to square borders
|
| 75 |
+
for i in range(n):
|
| 76 |
+
x, y = centers[i]
|
| 77 |
+
# Distance to borders
|
| 78 |
+
radii[i] = min(x, y, 1 - x, 1 - y)
|
| 79 |
+
|
| 80 |
+
# Then, limit by distance to other circles
|
| 81 |
+
# Each pair of circles with centers at distance d can have
|
| 82 |
+
# sum of radii at most d to avoid overlap
|
| 83 |
+
for i in range(n):
|
| 84 |
+
for j in range(i + 1, n):
|
| 85 |
+
dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2))
|
| 86 |
+
|
| 87 |
+
# If current radii would cause overlap
|
| 88 |
+
if radii[i] + radii[j] > dist:
|
| 89 |
+
# Scale both radii proportionally
|
| 90 |
+
scale = dist / (radii[i] + radii[j])
|
| 91 |
+
radii[i] *= scale
|
| 92 |
+
radii[j] *= scale
|
| 93 |
+
|
| 94 |
+
return radii
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
# EVOLVE-BLOCK-END
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
# This part remains fixed (not evolved)
|
| 101 |
+
def run_packing():
|
| 102 |
+
"""Run the circle packing constructor for n=26"""
|
| 103 |
+
centers, radii = construct_packing()
|
| 104 |
+
# Calculate the sum of radii
|
| 105 |
+
sum_radii = np.sum(radii)
|
| 106 |
+
return centers, radii, sum_radii
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/original.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# EVOLVE-BLOCK-START
|
| 2 |
+
"""Constructor-based circle packing for n=26 circles"""
|
| 3 |
+
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def construct_packing():
|
| 8 |
+
"""
|
| 9 |
+
Construct a specific arrangement of 26 circles in a unit square
|
| 10 |
+
that attempts to maximize the sum of their radii.
|
| 11 |
+
|
| 12 |
+
Returns:
|
| 13 |
+
Tuple of (centers, radii, sum_of_radii)
|
| 14 |
+
centers: np.array of shape (26, 2) with (x, y) coordinates
|
| 15 |
+
radii: np.array of shape (26) with radius of each circle
|
| 16 |
+
sum_of_radii: Sum of all radii
|
| 17 |
+
"""
|
| 18 |
+
# Initialize arrays for 26 circles
|
| 19 |
+
n = 26
|
| 20 |
+
centers = np.zeros((n, 2))
|
| 21 |
+
|
| 22 |
+
# Place circles in a structured pattern
|
| 23 |
+
# This is a simple pattern - evolution will improve this
|
| 24 |
+
|
| 25 |
+
# First, place a large circle in the center
|
| 26 |
+
centers[0] = [0.5, 0.5]
|
| 27 |
+
|
| 28 |
+
# Place 8 circles around it in a ring
|
| 29 |
+
for i in range(8):
|
| 30 |
+
angle = 2 * np.pi * i / 8
|
| 31 |
+
centers[i + 1] = [0.5 + 0.22 * np.cos(angle), 0.5 + 0.22 * np.sin(angle)]
|
| 32 |
+
|
| 33 |
+
# Place 16 more circles in an outer ring
|
| 34 |
+
for i in range(16):
|
| 35 |
+
angle = 2 * np.pi * i / 16
|
| 36 |
+
centers[i + 9] = [0.5 + 0.41 * np.cos(angle), 0.5 + 0.41 * np.sin(angle)]
|
| 37 |
+
|
| 38 |
+
# Additional positioning adjustment to make sure all circles
|
| 39 |
+
# are inside the square and don't overlap
|
| 40 |
+
# Clip to ensure everything is inside the unit square
|
| 41 |
+
centers = np.clip(centers, 0.01, 0.99)
|
| 42 |
+
|
| 43 |
+
# Compute maximum valid radii for this configuration
|
| 44 |
+
radii = compute_max_radii(centers)
|
| 45 |
+
return centers, radii
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def compute_max_radii(centers):
|
| 49 |
+
"""
|
| 50 |
+
Compute the maximum possible radii for each circle position
|
| 51 |
+
such that they don't overlap and stay within the unit square.
|
| 52 |
+
|
| 53 |
+
Args:
|
| 54 |
+
centers: np.array of shape (n, 2) with (x, y) coordinates
|
| 55 |
+
|
| 56 |
+
Returns:
|
| 57 |
+
np.array of shape (n) with radius of each circle
|
| 58 |
+
"""
|
| 59 |
+
n = centers.shape[0]
|
| 60 |
+
radii = np.ones(n)
|
| 61 |
+
|
| 62 |
+
# First, limit by distance to square borders
|
| 63 |
+
for i in range(n):
|
| 64 |
+
x, y = centers[i]
|
| 65 |
+
# Distance to borders
|
| 66 |
+
radii[i] = min(x, y, 1 - x, 1 - y)
|
| 67 |
+
|
| 68 |
+
# Then, limit by distance to other circles
|
| 69 |
+
# Each pair of circles with centers at distance d can have
|
| 70 |
+
# sum of radii at most d to avoid overlap
|
| 71 |
+
for i in range(n):
|
| 72 |
+
for j in range(i + 1, n):
|
| 73 |
+
dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2))
|
| 74 |
+
|
| 75 |
+
# If current radii would cause overlap
|
| 76 |
+
if radii[i] + radii[j] > dist:
|
| 77 |
+
# Scale both radii proportionally
|
| 78 |
+
scale = dist / (radii[i] + radii[j])
|
| 79 |
+
radii[i] *= scale
|
| 80 |
+
radii[j] *= scale
|
| 81 |
+
|
| 82 |
+
return radii
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
# EVOLVE-BLOCK-END
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
# This part remains fixed (not evolved)
|
| 89 |
+
def run_packing():
|
| 90 |
+
"""Run the circle packing constructor for n=26"""
|
| 91 |
+
centers, radii = construct_packing()
|
| 92 |
+
# Calculate the sum of radii
|
| 93 |
+
sum_radii = np.sum(radii)
|
| 94 |
+
return centers, radii, sum_radii
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/correct.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"correct": true,
|
| 3 |
+
"error": null
|
| 4 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/job_log.err
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning:
|
| 2 |
+
|
| 3 |
+
All support for the `google.generativeai` package has ended. It will no longer be receiving
|
| 4 |
+
updates or bug fixes. Please switch to the `google.genai` package as soon as possible.
|
| 5 |
+
See README for more details:
|
| 6 |
+
|
| 7 |
+
https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md
|
| 8 |
+
|
| 9 |
+
import google.generativeai as genai # type: ignore[import-not-found]
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/job_log.out
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/main.py
|
| 2 |
+
Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/results
|
| 3 |
+
Run 1/1 completed in 0.00 seconds
|
| 4 |
+
Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/extra.npz
|
| 5 |
+
Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/packing_viz.png
|
| 6 |
+
Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/correct.json
|
| 7 |
+
Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/metrics.json
|
| 8 |
+
Evaluation and Validation completed successfully.
|
| 9 |
+
Metrics:
|
| 10 |
+
combined_score: 1.853356327835797
|
| 11 |
+
public: {'centers_str': ' centers[0] = (0.1000, 0.1000)\n centers[1] = (0.1000, 0.3000)\n centers[2] = (0.1000, 0.5000)\n centers[3] = (0.1000, 0.7000)\n centers[4] = (0.1000, 0.9000)\n centers[5] = (0.3000, 0.1000)\n centers[6] = (0.3000, 0.3000)\n centers[7] = (0.3000, 0.5000)\n centers[8] = (0.3000, 0.7000)\n centers[9] = (0.3000, 0.9000)\n centers[10] = (0.5000, 0.0833)\n centers[11] = (0.5000, 0.2500)\n centers[12] = (0.5000, 0.4167)\n centers[13] = (0.5000, 0.5833)\n centers[14] = (0.5000, 0.7500)\n centers[15] = (0.5000, 0.9167)\n centers[16] = (0.7000, 0.1000)\n centers[17] = (0.7000, 0.3000)\n centers[18] = (0.7000, 0.5000)\n centers[19] = (0.7000, 0.7000)\n centers[20] = (0.7000, 0.9000)\n centers[21] = (0.9000, 0.1000)\n centers[22] = (0.9000, 0.3000)\n centers[23] = (0.9000, 0.5000)\n centers[24] = (0.9000, 0.7000)\n centers[25] = (0.9000, 0.9000)', 'num_circles': 26}
|
| 12 |
+
private: {'reported_sum_of_radii': 1.853356327835797}
|
| 13 |
+
visualization_path: <string_too_long_to_display>
|
| 14 |
+
execution_time_mean: 0.0020518279634416103
|
| 15 |
+
execution_time_std: 0.0
|
| 16 |
+
num_valid_runs: 1
|
| 17 |
+
num_invalid_runs: 0
|
| 18 |
+
all_validation_errors: []
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/metrics.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"combined_score": 1.853356327835797,
|
| 3 |
+
"public": {
|
| 4 |
+
"centers_str": " centers[0] = (0.1000, 0.1000)\n centers[1] = (0.1000, 0.3000)\n centers[2] = (0.1000, 0.5000)\n centers[3] = (0.1000, 0.7000)\n centers[4] = (0.1000, 0.9000)\n centers[5] = (0.3000, 0.1000)\n centers[6] = (0.3000, 0.3000)\n centers[7] = (0.3000, 0.5000)\n centers[8] = (0.3000, 0.7000)\n centers[9] = (0.3000, 0.9000)\n centers[10] = (0.5000, 0.0833)\n centers[11] = (0.5000, 0.2500)\n centers[12] = (0.5000, 0.4167)\n centers[13] = (0.5000, 0.5833)\n centers[14] = (0.5000, 0.7500)\n centers[15] = (0.5000, 0.9167)\n centers[16] = (0.7000, 0.1000)\n centers[17] = (0.7000, 0.3000)\n centers[18] = (0.7000, 0.5000)\n centers[19] = (0.7000, 0.7000)\n centers[20] = (0.7000, 0.9000)\n centers[21] = (0.9000, 0.1000)\n centers[22] = (0.9000, 0.3000)\n centers[23] = (0.9000, 0.5000)\n centers[24] = (0.9000, 0.7000)\n centers[25] = (0.9000, 0.9000)",
|
| 5 |
+
"num_circles": 26
|
| 6 |
+
},
|
| 7 |
+
"private": {
|
| 8 |
+
"reported_sum_of_radii": 1.853356327835797
|
| 9 |
+
},
|
| 10 |
+
"visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/packing_viz.png",
|
| 11 |
+
"execution_time_mean": 0.0020518279634416103,
|
| 12 |
+
"execution_time_std": 0.0,
|
| 13 |
+
"num_valid_runs": 1,
|
| 14 |
+
"num_invalid_runs": 0,
|
| 15 |
+
"all_validation_errors": []
|
| 16 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/search_replace.txt
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<NAME>
|
| 2 |
+
columnar_packing_55655
|
| 3 |
+
</NAME>
|
| 4 |
+
|
| 5 |
+
<DESCRIPTION>
|
| 6 |
+
The current circle packing uses a concentric ring structure, which is inefficient for a square container. The visualization clearly shows this inefficiency: there are large empty gaps, and the use of `np.clip` creates tiny, useless circles in the corners, drastically reducing the sum of radii.
|
| 7 |
+
|
| 8 |
+
To fix this, I am replacing the entire generation logic with a much more promising structure inspired by known good solutions for N=26. The new arrangement is a `5-5-6-5-5` column-based grid. This means there are 5 columns of circles; the outer four columns contain 5 circles each, and the central column contains 6 circles.
|
| 9 |
+
|
| 10 |
+
This change addresses the observed issues:
|
| 11 |
+
1. **Eliminates Clipping:** The new grid places centers within the `(0, 1)` square by construction, removing the need for `np.clip` and preventing the creation of artificially small circles.
|
| 12 |
+
2. **Improves Space Utilization:** A grid-like structure fills the square more evenly and densely than concentric rings.
|
| 13 |
+
3. **Adopts a Proven Heuristic:** This columnar arrangement is a known-good heuristic for packing this number of circles, which should lead to a significantly larger sum of radii.
|
| 14 |
+
|
| 15 |
+
The coordinates for the grid points are chosen based on simple, regular spacing (`np.linspace`) to create a solid baseline for the `compute_max_radii` function to work with. This overhaul should substantially improve performance.
|
| 16 |
+
</DESCRIPTION>
|
| 17 |
+
|
| 18 |
+
<DIFF>
|
| 19 |
+
<<<<<<< SEARCH
|
| 20 |
+
"""Constructor-based circle packing for n=26 circles"""
|
| 21 |
+
|
| 22 |
+
import numpy as np
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def construct_packing():
|
| 26 |
+
"""
|
| 27 |
+
Construct a specific arrangement of 26 circles in a unit square
|
| 28 |
+
that attempts to maximize the sum of their radii.
|
| 29 |
+
|
| 30 |
+
Returns:
|
| 31 |
+
Tuple of (centers, radii, sum_of_radii)
|
| 32 |
+
centers: np.array of shape (26, 2) with (x, y) coordinates
|
| 33 |
+
radii: np.array of shape (26) with radius of each circle
|
| 34 |
+
sum_of_radii: Sum of all radii
|
| 35 |
+
"""
|
| 36 |
+
# Initialize arrays for 26 circles
|
| 37 |
+
n = 26
|
| 38 |
+
centers = np.zeros((n, 2))
|
| 39 |
+
|
| 40 |
+
# Place circles in a structured pattern
|
| 41 |
+
# This is a simple pattern - evolution will improve this
|
| 42 |
+
|
| 43 |
+
# First, place a large circle in the center
|
| 44 |
+
centers[0] = [0.5, 0.5]
|
| 45 |
+
|
| 46 |
+
# Place 8 circles around it in a ring
|
| 47 |
+
for i in range(8):
|
| 48 |
+
angle = 2 * np.pi * i / 8
|
| 49 |
+
centers[i + 1] = [0.5 + 0.22 * np.cos(angle), 0.5 + 0.22 * np.sin(angle)]
|
| 50 |
+
|
| 51 |
+
# Place 16 more circles in an outer ring
|
| 52 |
+
for i in range(16):
|
| 53 |
+
angle = 2 * np.pi * i / 16
|
| 54 |
+
centers[i + 9] = [0.5 + 0.41 * np.cos(angle), 0.5 + 0.41 * np.sin(angle)]
|
| 55 |
+
|
| 56 |
+
# Additional positioning adjustment to make sure all circles
|
| 57 |
+
# are inside the square and don't overlap
|
| 58 |
+
# Clip to ensure everything is inside the unit square
|
| 59 |
+
centers = np.clip(centers, 0.01, 0.99)
|
| 60 |
+
|
| 61 |
+
# Compute maximum valid radii for this configuration
|
| 62 |
+
radii = compute_max_radii(centers)
|
| 63 |
+
return centers, radii
|
| 64 |
+
=======
|
| 65 |
+
"""Constructor-based circle packing for n=26 circles"""
|
| 66 |
+
|
| 67 |
+
import numpy as np
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def construct_packing():
|
| 71 |
+
"""
|
| 72 |
+
Construct a specific arrangement of 26 circles in a unit square
|
| 73 |
+
that attempts to maximize the sum of their radii.
|
| 74 |
+
|
| 75 |
+
Returns:
|
| 76 |
+
Tuple of (centers, radii, sum_of_radii)
|
| 77 |
+
centers: np.array of shape (26, 2) with (x, y) coordinates
|
| 78 |
+
radii: np.array of shape (26) with radius of each circle
|
| 79 |
+
sum_of_radii: Sum of all radii
|
| 80 |
+
"""
|
| 81 |
+
# Initialize arrays for 26 circles
|
| 82 |
+
n = 26
|
| 83 |
+
centers = np.zeros((n, 2))
|
| 84 |
+
|
| 85 |
+
# Using a 5-5-6-5-5 column-like structure.
|
| 86 |
+
# This structure is inspired by known good packings for N=26 and provides
|
| 87 |
+
# much better space utilization than the previous concentric ring model.
|
| 88 |
+
# It avoids the need for clipping, which created tiny, inefficient circles.
|
| 89 |
+
|
| 90 |
+
# x-coordinates for the 5 columns
|
| 91 |
+
x_cols = np.linspace(0.1, 0.9, 5)
|
| 92 |
+
|
| 93 |
+
# y-coordinates for columns with 5 circles
|
| 94 |
+
y_5 = np.linspace(0.1, 0.9, 5)
|
| 95 |
+
|
| 96 |
+
# y-coordinates for the central column with 6 circles
|
| 97 |
+
y_6 = np.linspace(1/12, 11/12, 6)
|
| 98 |
+
|
| 99 |
+
count = 0
|
| 100 |
+
# Arrange circles column by column
|
| 101 |
+
for i in range(5):
|
| 102 |
+
x = x_cols[i]
|
| 103 |
+
|
| 104 |
+
# The central column (i=2) has 6 circles
|
| 105 |
+
if i == 2:
|
| 106 |
+
for y in y_6:
|
| 107 |
+
centers[count] = [x, y]
|
| 108 |
+
count += 1
|
| 109 |
+
# The other four columns have 5 circles each
|
| 110 |
+
else:
|
| 111 |
+
for y in y_5:
|
| 112 |
+
centers[count] = [x, y]
|
| 113 |
+
count += 1
|
| 114 |
+
|
| 115 |
+
# This construction places all centers within the (0,1) square,
|
| 116 |
+
# so no clipping is necessary.
|
| 117 |
+
|
| 118 |
+
# Compute maximum valid radii for this configuration
|
| 119 |
+
radii = compute_max_radii(centers)
|
| 120 |
+
return centers, radii
|
| 121 |
+
>>>>>>> REPLACE
|
| 122 |
+
</DIFF>
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/__pycache__/main.cpython-311.pyc
ADDED
|
Binary file (9.22 kB). View file
|
|
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/edit.diff
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
--- a/original.py
|
| 2 |
+
+++ b/original.py
|
| 3 |
+
@@ -1,186 +1,214 @@
|
| 4 |
+
# EVOLVE-BLOCK-START
|
| 5 |
+
"""Constructor-based circle packing for n=26 circles"""
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def construct_packing():
|
| 11 |
+
"""
|
| 12 |
+
Construct a specific arrangement of 26 circles in a unit square
|
| 13 |
+
that attempts to maximize the sum of their radii.
|
| 14 |
+
|
| 15 |
+
Returns:
|
| 16 |
+
Tuple of (centers, radii, sum_of_radii)
|
| 17 |
+
centers: np.array of shape (26, 2) with (x, y) coordinates
|
| 18 |
+
radii: np.array of shape (26) with radius of each circle
|
| 19 |
+
sum_of_radii: Sum of all radii
|
| 20 |
+
"""
|
| 21 |
+
# Initialize arrays for 26 circles
|
| 22 |
+
n = 26
|
| 23 |
+
centers = np.zeros((n, 2))
|
| 24 |
+
|
| 25 |
+
# 1. Start with the 25 centers of a 5x5 grid.
|
| 26 |
+
x_coords = np.linspace(0.1, 0.9, 5)
|
| 27 |
+
y_coords = np.linspace(0.1, 0.9, 5)
|
| 28 |
+
xx, yy = np.meshgrid(x_coords, y_coords)
|
| 29 |
+
base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T
|
| 30 |
+
|
| 31 |
+
# 2. Define an ASYMMETRIC center for the void.
|
| 32 |
+
# Breaking the initial symmetry by using an off-center void at (0.4, 0.2)
|
| 33 |
+
# prevents the relaxation from getting stuck in an overly-ordered local optimum.
|
| 34 |
+
void_center = np.array([0.4, 0.2])
|
| 35 |
+
|
| 36 |
+
# 3. Deform the 25 grid points with a Gaussian repulsive push from the void center.
|
| 37 |
+
# This pushes nearby circles away to make more room.
|
| 38 |
+
deformed_centers_25 = np.copy(base_centers_25)
|
| 39 |
+
|
| 40 |
+
# Hyperparameters for the Gaussian push:
|
| 41 |
+
amplitude = 0.06 # The maximum distance to push a circle. Increased to create a larger void.
|
| 42 |
+
sigma = 0.15 # The "spread" of the push, controlling its influence range.
|
| 43 |
+
|
| 44 |
+
for i in range(25):
|
| 45 |
+
pos_vector = base_centers_25[i] - void_center
|
| 46 |
+
dist_sq = np.sum(pos_vector**2)
|
| 47 |
+
|
| 48 |
+
# Gaussian function defines the push magnitude based on distance from the void center.
|
| 49 |
+
push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2))
|
| 50 |
+
|
| 51 |
+
# The push is directed radially away from the void center.
|
| 52 |
+
if np.linalg.norm(pos_vector) > 1e-9:
|
| 53 |
+
direction = pos_vector / np.linalg.norm(pos_vector)
|
| 54 |
+
displacement = direction * push_magnitude
|
| 55 |
+
deformed_centers_25[i] += displacement
|
| 56 |
+
|
| 57 |
+
# 4. Place the deformed 25 circles and add the 26th in the now-enlarged void.
|
| 58 |
+
centers[:25] = deformed_centers_25
|
| 59 |
+
centers[25] = void_center
|
| 60 |
+
|
| 61 |
+
# Clip centers to ensure they stay within the square, although the push is gentle.
|
| 62 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 63 |
+
|
| 64 |
+
# 5. Two-Stage Adaptive Force-Directed Relaxation.
|
| 65 |
+
# This approach uses a high-energy "exploration" phase to break symmetry
|
| 66 |
+
# and find a good general configuration, followed by a low-energy
|
| 67 |
+
# "refinement" phase to fine-tune the positions.
|
| 68 |
+
|
| 69 |
+
# Stage 1: High-Energy Exploration
|
| 70 |
+
# This stage uses strong forces and a large step size to quickly move circles
|
| 71 |
+
# out of the initial grid structure and explore new arrangements.
|
| 72 |
+
- exploration_iters = 250
|
| 73 |
+
+ exploration_iters = 300
|
| 74 |
+
exploration_step_size = 0.003
|
| 75 |
+
- exploration_repulsion_strength = 0.02
|
| 76 |
+
+ exploration_repulsion_strength = 0.025
|
| 77 |
+
exploration_boundary_strength = 0.1
|
| 78 |
+
exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement
|
| 79 |
+
boundary_margin = 0.04 # Use a smaller margin to utilize edge space better
|
| 80 |
+
|
| 81 |
+
for _ in range(exploration_iters):
|
| 82 |
+
forces = np.zeros_like(centers)
|
| 83 |
+
for i in range(n):
|
| 84 |
+
for j in range(i + 1, n):
|
| 85 |
+
vec = centers[i] - centers[j]
|
| 86 |
+
dist = np.linalg.norm(vec)
|
| 87 |
+
if 0 < dist < exploration_repulsion_threshold:
|
| 88 |
+
force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist
|
| 89 |
+
force_vec = force_mag * (vec / dist)
|
| 90 |
+
forces[i] += force_vec
|
| 91 |
+
forces[j] -= force_vec
|
| 92 |
+
for i in range(n):
|
| 93 |
+
x, y = centers[i]
|
| 94 |
+
if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x)
|
| 95 |
+
if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin))
|
| 96 |
+
if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y)
|
| 97 |
+
if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin))
|
| 98 |
+
centers += exploration_step_size * forces
|
| 99 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 100 |
+
|
| 101 |
+
# Stage 2: Low-Energy Refinement
|
| 102 |
+
# This stage uses more iterations with weaker forces and a smaller step size
|
| 103 |
+
# to settle the circles into a dense, stable local optimum.
|
| 104 |
+
refinement_iters = 500
|
| 105 |
+
refinement_step_size = 0.0005
|
| 106 |
+
- refinement_repulsion_strength = 0.008
|
| 107 |
+
+ refinement_repulsion_strength = 0.01
|
| 108 |
+
refinement_boundary_strength = 0.04
|
| 109 |
+
refinement_repulsion_threshold = 0.185 # Tighter threshold for settling
|
| 110 |
+
|
| 111 |
+
for _ in range(refinement_iters):
|
| 112 |
+
forces = np.zeros_like(centers)
|
| 113 |
+
for i in range(n):
|
| 114 |
+
for j in range(i + 1, n):
|
| 115 |
+
vec = centers[i] - centers[j]
|
| 116 |
+
dist = np.linalg.norm(vec)
|
| 117 |
+
if 0 < dist < refinement_repulsion_threshold:
|
| 118 |
+
force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist
|
| 119 |
+
force_vec = force_mag * (vec / dist)
|
| 120 |
+
forces[i] += force_vec
|
| 121 |
+
forces[j] -= force_vec
|
| 122 |
+
for i in range(n):
|
| 123 |
+
x, y = centers[i]
|
| 124 |
+
if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x)
|
| 125 |
+
if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin))
|
| 126 |
+
if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y)
|
| 127 |
+
if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin))
|
| 128 |
+
centers += refinement_step_size * forces
|
| 129 |
+
+ centers = np.clip(centers, 0.0, 1.0)
|
| 130 |
+
+
|
| 131 |
+
+ # Stage 3: Ultra-Low-Energy Annealing ("Polishing")
|
| 132 |
+
+ # This stage uses very weak forces and many iterations for final micro-adjustments.
|
| 133 |
+
+ annealing_iters = 800
|
| 134 |
+
+ annealing_step_size = 0.0001
|
| 135 |
+
+ annealing_repulsion_strength = 0.004
|
| 136 |
+
+ annealing_boundary_strength = 0.02
|
| 137 |
+
+ annealing_repulsion_threshold = 0.18 # Tighter threshold for final packing
|
| 138 |
+
+
|
| 139 |
+
+ for _ in range(annealing_iters):
|
| 140 |
+
+ forces = np.zeros_like(centers)
|
| 141 |
+
+ for i in range(n):
|
| 142 |
+
+ for j in range(i + 1, n):
|
| 143 |
+
+ vec = centers[i] - centers[j]
|
| 144 |
+
+ dist = np.linalg.norm(vec)
|
| 145 |
+
+ if 0 < dist < annealing_repulsion_threshold:
|
| 146 |
+
+ force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist
|
| 147 |
+
+ force_vec = force_mag * (vec / dist)
|
| 148 |
+
+ forces[i] += force_vec
|
| 149 |
+
+ forces[j] -= force_vec
|
| 150 |
+
+ for i in range(n):
|
| 151 |
+
+ x, y = centers[i]
|
| 152 |
+
+ if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x)
|
| 153 |
+
+ if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin))
|
| 154 |
+
+ if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y)
|
| 155 |
+
+ if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin))
|
| 156 |
+
+ centers += annealing_step_size * forces
|
| 157 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 158 |
+
|
| 159 |
+
# 6. Compute maximum valid radii for the refined configuration.
|
| 160 |
+
radii = compute_max_radii(centers)
|
| 161 |
+
return centers, radii
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
def compute_max_radii(centers):
|
| 165 |
+
"""
|
| 166 |
+
Compute the maximum possible radii for each circle position
|
| 167 |
+
such that they don't overlap and stay within the unit square. This version
|
| 168 |
+
iteratively resolves conflicts until convergence for a more accurate result.
|
| 169 |
+
|
| 170 |
+
Args:
|
| 171 |
+
centers: np.array of shape (n, 2) with (x, y) coordinates
|
| 172 |
+
|
| 173 |
+
Returns:
|
| 174 |
+
np.array of shape (n) with radius of each circle
|
| 175 |
+
"""
|
| 176 |
+
n = centers.shape[0]
|
| 177 |
+
radii = np.zeros(n)
|
| 178 |
+
|
| 179 |
+
# First, limit by distance to square borders
|
| 180 |
+
for i in range(n):
|
| 181 |
+
x, y = centers[i]
|
| 182 |
+
radii[i] = min(x, y, 1 - x, 1 - y)
|
| 183 |
+
|
| 184 |
+
# Iteratively limit by distance to other circles, allowing constraints to propagate
|
| 185 |
+
for _ in range(300): # Iterate to ensure convergence
|
| 186 |
+
changes_made = False
|
| 187 |
+
for i in range(n):
|
| 188 |
+
for j in range(i + 1, n):
|
| 189 |
+
dist = np.linalg.norm(centers[i] - centers[j])
|
| 190 |
+
|
| 191 |
+
# If current radii cause overlap
|
| 192 |
+
if radii[i] + radii[j] > dist:
|
| 193 |
+
sum_r = radii[i] + radii[j]
|
| 194 |
+
if sum_r > 1e-9: # Avoid division by zero for coincident centers
|
| 195 |
+
# Scale both radii proportionally to resolve overlap
|
| 196 |
+
scale = dist / sum_r
|
| 197 |
+
ri_new = radii[i] * scale
|
| 198 |
+
rj_new = radii[j] * scale
|
| 199 |
+
|
| 200 |
+
# Check for significant change to set the flag
|
| 201 |
+
if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9:
|
| 202 |
+
radii[i] = ri_new
|
| 203 |
+
radii[j] = rj_new
|
| 204 |
+
changes_made = True
|
| 205 |
+
if not changes_made:
|
| 206 |
+
break # Exit early if the configuration is stable
|
| 207 |
+
|
| 208 |
+
return radii
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
# EVOLVE-BLOCK-END
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
# This part remains fixed (not evolved)
|
| 215 |
+
def run_packing():
|
| 216 |
+
"""Run the circle packing constructor for n=26"""
|
| 217 |
+
centers, radii = construct_packing()
|
| 218 |
+
# Calculate the sum of radii
|
| 219 |
+
sum_radii = np.sum(radii)
|
| 220 |
+
return centers, radii, sum_radii
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/main.py
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# EVOLVE-BLOCK-START
|
| 2 |
+
"""Constructor-based circle packing for n=26 circles"""
|
| 3 |
+
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def construct_packing():
|
| 8 |
+
"""
|
| 9 |
+
Construct a specific arrangement of 26 circles in a unit square
|
| 10 |
+
that attempts to maximize the sum of their radii.
|
| 11 |
+
|
| 12 |
+
Returns:
|
| 13 |
+
Tuple of (centers, radii, sum_of_radii)
|
| 14 |
+
centers: np.array of shape (26, 2) with (x, y) coordinates
|
| 15 |
+
radii: np.array of shape (26) with radius of each circle
|
| 16 |
+
sum_of_radii: Sum of all radii
|
| 17 |
+
"""
|
| 18 |
+
# Initialize arrays for 26 circles
|
| 19 |
+
n = 26
|
| 20 |
+
centers = np.zeros((n, 2))
|
| 21 |
+
|
| 22 |
+
# 1. Start with the 25 centers of a 5x5 grid.
|
| 23 |
+
x_coords = np.linspace(0.1, 0.9, 5)
|
| 24 |
+
y_coords = np.linspace(0.1, 0.9, 5)
|
| 25 |
+
xx, yy = np.meshgrid(x_coords, y_coords)
|
| 26 |
+
base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T
|
| 27 |
+
|
| 28 |
+
# 2. Define an ASYMMETRIC center for the void.
|
| 29 |
+
# Breaking the initial symmetry by using an off-center void at (0.4, 0.2)
|
| 30 |
+
# prevents the relaxation from getting stuck in an overly-ordered local optimum.
|
| 31 |
+
void_center = np.array([0.4, 0.2])
|
| 32 |
+
|
| 33 |
+
# 3. Deform the 25 grid points with a Gaussian repulsive push from the void center.
|
| 34 |
+
# This pushes nearby circles away to make more room.
|
| 35 |
+
deformed_centers_25 = np.copy(base_centers_25)
|
| 36 |
+
|
| 37 |
+
# Hyperparameters for the Gaussian push:
|
| 38 |
+
amplitude = 0.06 # The maximum distance to push a circle. Increased to create a larger void.
|
| 39 |
+
sigma = 0.15 # The "spread" of the push, controlling its influence range.
|
| 40 |
+
|
| 41 |
+
for i in range(25):
|
| 42 |
+
pos_vector = base_centers_25[i] - void_center
|
| 43 |
+
dist_sq = np.sum(pos_vector**2)
|
| 44 |
+
|
| 45 |
+
# Gaussian function defines the push magnitude based on distance from the void center.
|
| 46 |
+
push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2))
|
| 47 |
+
|
| 48 |
+
# The push is directed radially away from the void center.
|
| 49 |
+
if np.linalg.norm(pos_vector) > 1e-9:
|
| 50 |
+
direction = pos_vector / np.linalg.norm(pos_vector)
|
| 51 |
+
displacement = direction * push_magnitude
|
| 52 |
+
deformed_centers_25[i] += displacement
|
| 53 |
+
|
| 54 |
+
# 4. Place the deformed 25 circles and add the 26th in the now-enlarged void.
|
| 55 |
+
centers[:25] = deformed_centers_25
|
| 56 |
+
centers[25] = void_center
|
| 57 |
+
|
| 58 |
+
# Clip centers to ensure they stay within the square, although the push is gentle.
|
| 59 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 60 |
+
|
| 61 |
+
# 5. Two-Stage Adaptive Force-Directed Relaxation.
|
| 62 |
+
# This approach uses a high-energy "exploration" phase to break symmetry
|
| 63 |
+
# and find a good general configuration, followed by a low-energy
|
| 64 |
+
# "refinement" phase to fine-tune the positions.
|
| 65 |
+
|
| 66 |
+
# Stage 1: High-Energy Exploration
|
| 67 |
+
# This stage uses strong forces and a large step size to quickly move circles
|
| 68 |
+
# out of the initial grid structure and explore new arrangements.
|
| 69 |
+
exploration_iters = 300
|
| 70 |
+
exploration_step_size = 0.003
|
| 71 |
+
exploration_repulsion_strength = 0.025
|
| 72 |
+
exploration_boundary_strength = 0.1
|
| 73 |
+
exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement
|
| 74 |
+
boundary_margin = 0.04 # Use a smaller margin to utilize edge space better
|
| 75 |
+
|
| 76 |
+
for _ in range(exploration_iters):
|
| 77 |
+
forces = np.zeros_like(centers)
|
| 78 |
+
for i in range(n):
|
| 79 |
+
for j in range(i + 1, n):
|
| 80 |
+
vec = centers[i] - centers[j]
|
| 81 |
+
dist = np.linalg.norm(vec)
|
| 82 |
+
if 0 < dist < exploration_repulsion_threshold:
|
| 83 |
+
force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist
|
| 84 |
+
force_vec = force_mag * (vec / dist)
|
| 85 |
+
forces[i] += force_vec
|
| 86 |
+
forces[j] -= force_vec
|
| 87 |
+
for i in range(n):
|
| 88 |
+
x, y = centers[i]
|
| 89 |
+
if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x)
|
| 90 |
+
if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin))
|
| 91 |
+
if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y)
|
| 92 |
+
if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin))
|
| 93 |
+
centers += exploration_step_size * forces
|
| 94 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 95 |
+
|
| 96 |
+
# Stage 2: Low-Energy Refinement
|
| 97 |
+
# This stage uses more iterations with weaker forces and a smaller step size
|
| 98 |
+
# to settle the circles into a dense, stable local optimum.
|
| 99 |
+
refinement_iters = 500
|
| 100 |
+
refinement_step_size = 0.0005
|
| 101 |
+
refinement_repulsion_strength = 0.01
|
| 102 |
+
refinement_boundary_strength = 0.04
|
| 103 |
+
refinement_repulsion_threshold = 0.185 # Tighter threshold for settling
|
| 104 |
+
|
| 105 |
+
for _ in range(refinement_iters):
|
| 106 |
+
forces = np.zeros_like(centers)
|
| 107 |
+
for i in range(n):
|
| 108 |
+
for j in range(i + 1, n):
|
| 109 |
+
vec = centers[i] - centers[j]
|
| 110 |
+
dist = np.linalg.norm(vec)
|
| 111 |
+
if 0 < dist < refinement_repulsion_threshold:
|
| 112 |
+
force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist
|
| 113 |
+
force_vec = force_mag * (vec / dist)
|
| 114 |
+
forces[i] += force_vec
|
| 115 |
+
forces[j] -= force_vec
|
| 116 |
+
for i in range(n):
|
| 117 |
+
x, y = centers[i]
|
| 118 |
+
if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x)
|
| 119 |
+
if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin))
|
| 120 |
+
if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y)
|
| 121 |
+
if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin))
|
| 122 |
+
centers += refinement_step_size * forces
|
| 123 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 124 |
+
|
| 125 |
+
# Stage 3: Ultra-Low-Energy Annealing ("Polishing")
|
| 126 |
+
# This stage uses very weak forces and many iterations for final micro-adjustments.
|
| 127 |
+
annealing_iters = 800
|
| 128 |
+
annealing_step_size = 0.0001
|
| 129 |
+
annealing_repulsion_strength = 0.004
|
| 130 |
+
annealing_boundary_strength = 0.02
|
| 131 |
+
annealing_repulsion_threshold = 0.18 # Tighter threshold for final packing
|
| 132 |
+
|
| 133 |
+
for _ in range(annealing_iters):
|
| 134 |
+
forces = np.zeros_like(centers)
|
| 135 |
+
for i in range(n):
|
| 136 |
+
for j in range(i + 1, n):
|
| 137 |
+
vec = centers[i] - centers[j]
|
| 138 |
+
dist = np.linalg.norm(vec)
|
| 139 |
+
if 0 < dist < annealing_repulsion_threshold:
|
| 140 |
+
force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist
|
| 141 |
+
force_vec = force_mag * (vec / dist)
|
| 142 |
+
forces[i] += force_vec
|
| 143 |
+
forces[j] -= force_vec
|
| 144 |
+
for i in range(n):
|
| 145 |
+
x, y = centers[i]
|
| 146 |
+
if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x)
|
| 147 |
+
if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin))
|
| 148 |
+
if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y)
|
| 149 |
+
if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin))
|
| 150 |
+
centers += annealing_step_size * forces
|
| 151 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 152 |
+
|
| 153 |
+
# 6. Compute maximum valid radii for the refined configuration.
|
| 154 |
+
radii = compute_max_radii(centers)
|
| 155 |
+
return centers, radii
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def compute_max_radii(centers):
|
| 159 |
+
"""
|
| 160 |
+
Compute the maximum possible radii for each circle position
|
| 161 |
+
such that they don't overlap and stay within the unit square. This version
|
| 162 |
+
iteratively resolves conflicts until convergence for a more accurate result.
|
| 163 |
+
|
| 164 |
+
Args:
|
| 165 |
+
centers: np.array of shape (n, 2) with (x, y) coordinates
|
| 166 |
+
|
| 167 |
+
Returns:
|
| 168 |
+
np.array of shape (n) with radius of each circle
|
| 169 |
+
"""
|
| 170 |
+
n = centers.shape[0]
|
| 171 |
+
radii = np.zeros(n)
|
| 172 |
+
|
| 173 |
+
# First, limit by distance to square borders
|
| 174 |
+
for i in range(n):
|
| 175 |
+
x, y = centers[i]
|
| 176 |
+
radii[i] = min(x, y, 1 - x, 1 - y)
|
| 177 |
+
|
| 178 |
+
# Iteratively limit by distance to other circles, allowing constraints to propagate
|
| 179 |
+
for _ in range(300): # Iterate to ensure convergence
|
| 180 |
+
changes_made = False
|
| 181 |
+
for i in range(n):
|
| 182 |
+
for j in range(i + 1, n):
|
| 183 |
+
dist = np.linalg.norm(centers[i] - centers[j])
|
| 184 |
+
|
| 185 |
+
# If current radii cause overlap
|
| 186 |
+
if radii[i] + radii[j] > dist:
|
| 187 |
+
sum_r = radii[i] + radii[j]
|
| 188 |
+
if sum_r > 1e-9: # Avoid division by zero for coincident centers
|
| 189 |
+
# Scale both radii proportionally to resolve overlap
|
| 190 |
+
scale = dist / sum_r
|
| 191 |
+
ri_new = radii[i] * scale
|
| 192 |
+
rj_new = radii[j] * scale
|
| 193 |
+
|
| 194 |
+
# Check for significant change to set the flag
|
| 195 |
+
if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9:
|
| 196 |
+
radii[i] = ri_new
|
| 197 |
+
radii[j] = rj_new
|
| 198 |
+
changes_made = True
|
| 199 |
+
if not changes_made:
|
| 200 |
+
break # Exit early if the configuration is stable
|
| 201 |
+
|
| 202 |
+
return radii
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
# EVOLVE-BLOCK-END
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
# This part remains fixed (not evolved)
|
| 209 |
+
def run_packing():
|
| 210 |
+
"""Run the circle packing constructor for n=26"""
|
| 211 |
+
centers, radii = construct_packing()
|
| 212 |
+
# Calculate the sum of radii
|
| 213 |
+
sum_radii = np.sum(radii)
|
| 214 |
+
return centers, radii, sum_radii
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/original.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# EVOLVE-BLOCK-START
|
| 2 |
+
"""Constructor-based circle packing for n=26 circles"""
|
| 3 |
+
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def construct_packing():
|
| 8 |
+
"""
|
| 9 |
+
Construct a specific arrangement of 26 circles in a unit square
|
| 10 |
+
that attempts to maximize the sum of their radii.
|
| 11 |
+
|
| 12 |
+
Returns:
|
| 13 |
+
Tuple of (centers, radii, sum_of_radii)
|
| 14 |
+
centers: np.array of shape (26, 2) with (x, y) coordinates
|
| 15 |
+
radii: np.array of shape (26) with radius of each circle
|
| 16 |
+
sum_of_radii: Sum of all radii
|
| 17 |
+
"""
|
| 18 |
+
# Initialize arrays for 26 circles
|
| 19 |
+
n = 26
|
| 20 |
+
centers = np.zeros((n, 2))
|
| 21 |
+
|
| 22 |
+
# 1. Start with the 25 centers of a 5x5 grid.
|
| 23 |
+
x_coords = np.linspace(0.1, 0.9, 5)
|
| 24 |
+
y_coords = np.linspace(0.1, 0.9, 5)
|
| 25 |
+
xx, yy = np.meshgrid(x_coords, y_coords)
|
| 26 |
+
base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T
|
| 27 |
+
|
| 28 |
+
# 2. Define an ASYMMETRIC center for the void.
|
| 29 |
+
# Breaking the initial symmetry by using an off-center void at (0.4, 0.2)
|
| 30 |
+
# prevents the relaxation from getting stuck in an overly-ordered local optimum.
|
| 31 |
+
void_center = np.array([0.4, 0.2])
|
| 32 |
+
|
| 33 |
+
# 3. Deform the 25 grid points with a Gaussian repulsive push from the void center.
|
| 34 |
+
# This pushes nearby circles away to make more room.
|
| 35 |
+
deformed_centers_25 = np.copy(base_centers_25)
|
| 36 |
+
|
| 37 |
+
# Hyperparameters for the Gaussian push:
|
| 38 |
+
amplitude = 0.06 # The maximum distance to push a circle. Increased to create a larger void.
|
| 39 |
+
sigma = 0.15 # The "spread" of the push, controlling its influence range.
|
| 40 |
+
|
| 41 |
+
for i in range(25):
|
| 42 |
+
pos_vector = base_centers_25[i] - void_center
|
| 43 |
+
dist_sq = np.sum(pos_vector**2)
|
| 44 |
+
|
| 45 |
+
# Gaussian function defines the push magnitude based on distance from the void center.
|
| 46 |
+
push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2))
|
| 47 |
+
|
| 48 |
+
# The push is directed radially away from the void center.
|
| 49 |
+
if np.linalg.norm(pos_vector) > 1e-9:
|
| 50 |
+
direction = pos_vector / np.linalg.norm(pos_vector)
|
| 51 |
+
displacement = direction * push_magnitude
|
| 52 |
+
deformed_centers_25[i] += displacement
|
| 53 |
+
|
| 54 |
+
# 4. Place the deformed 25 circles and add the 26th in the now-enlarged void.
|
| 55 |
+
centers[:25] = deformed_centers_25
|
| 56 |
+
centers[25] = void_center
|
| 57 |
+
|
| 58 |
+
# Clip centers to ensure they stay within the square, although the push is gentle.
|
| 59 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 60 |
+
|
| 61 |
+
# 5. Two-Stage Adaptive Force-Directed Relaxation.
|
| 62 |
+
# This approach uses a high-energy "exploration" phase to break symmetry
|
| 63 |
+
# and find a good general configuration, followed by a low-energy
|
| 64 |
+
# "refinement" phase to fine-tune the positions.
|
| 65 |
+
|
| 66 |
+
# Stage 1: High-Energy Exploration
|
| 67 |
+
# This stage uses strong forces and a large step size to quickly move circles
|
| 68 |
+
# out of the initial grid structure and explore new arrangements.
|
| 69 |
+
exploration_iters = 250
|
| 70 |
+
exploration_step_size = 0.003
|
| 71 |
+
exploration_repulsion_strength = 0.02
|
| 72 |
+
exploration_boundary_strength = 0.1
|
| 73 |
+
exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement
|
| 74 |
+
boundary_margin = 0.04 # Use a smaller margin to utilize edge space better
|
| 75 |
+
|
| 76 |
+
for _ in range(exploration_iters):
|
| 77 |
+
forces = np.zeros_like(centers)
|
| 78 |
+
for i in range(n):
|
| 79 |
+
for j in range(i + 1, n):
|
| 80 |
+
vec = centers[i] - centers[j]
|
| 81 |
+
dist = np.linalg.norm(vec)
|
| 82 |
+
if 0 < dist < exploration_repulsion_threshold:
|
| 83 |
+
force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist
|
| 84 |
+
force_vec = force_mag * (vec / dist)
|
| 85 |
+
forces[i] += force_vec
|
| 86 |
+
forces[j] -= force_vec
|
| 87 |
+
for i in range(n):
|
| 88 |
+
x, y = centers[i]
|
| 89 |
+
if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x)
|
| 90 |
+
if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin))
|
| 91 |
+
if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y)
|
| 92 |
+
if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin))
|
| 93 |
+
centers += exploration_step_size * forces
|
| 94 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 95 |
+
|
| 96 |
+
# Stage 2: Low-Energy Refinement
|
| 97 |
+
# This stage uses more iterations with weaker forces and a smaller step size
|
| 98 |
+
# to settle the circles into a dense, stable local optimum.
|
| 99 |
+
refinement_iters = 500
|
| 100 |
+
refinement_step_size = 0.0005
|
| 101 |
+
refinement_repulsion_strength = 0.008
|
| 102 |
+
refinement_boundary_strength = 0.04
|
| 103 |
+
refinement_repulsion_threshold = 0.185 # Tighter threshold for settling
|
| 104 |
+
|
| 105 |
+
for _ in range(refinement_iters):
|
| 106 |
+
forces = np.zeros_like(centers)
|
| 107 |
+
for i in range(n):
|
| 108 |
+
for j in range(i + 1, n):
|
| 109 |
+
vec = centers[i] - centers[j]
|
| 110 |
+
dist = np.linalg.norm(vec)
|
| 111 |
+
if 0 < dist < refinement_repulsion_threshold:
|
| 112 |
+
force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist
|
| 113 |
+
force_vec = force_mag * (vec / dist)
|
| 114 |
+
forces[i] += force_vec
|
| 115 |
+
forces[j] -= force_vec
|
| 116 |
+
for i in range(n):
|
| 117 |
+
x, y = centers[i]
|
| 118 |
+
if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x)
|
| 119 |
+
if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin))
|
| 120 |
+
if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y)
|
| 121 |
+
if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin))
|
| 122 |
+
centers += refinement_step_size * forces
|
| 123 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 124 |
+
|
| 125 |
+
# 6. Compute maximum valid radii for the refined configuration.
|
| 126 |
+
radii = compute_max_radii(centers)
|
| 127 |
+
return centers, radii
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
def compute_max_radii(centers):
|
| 131 |
+
"""
|
| 132 |
+
Compute the maximum possible radii for each circle position
|
| 133 |
+
such that they don't overlap and stay within the unit square. This version
|
| 134 |
+
iteratively resolves conflicts until convergence for a more accurate result.
|
| 135 |
+
|
| 136 |
+
Args:
|
| 137 |
+
centers: np.array of shape (n, 2) with (x, y) coordinates
|
| 138 |
+
|
| 139 |
+
Returns:
|
| 140 |
+
np.array of shape (n) with radius of each circle
|
| 141 |
+
"""
|
| 142 |
+
n = centers.shape[0]
|
| 143 |
+
radii = np.zeros(n)
|
| 144 |
+
|
| 145 |
+
# First, limit by distance to square borders
|
| 146 |
+
for i in range(n):
|
| 147 |
+
x, y = centers[i]
|
| 148 |
+
radii[i] = min(x, y, 1 - x, 1 - y)
|
| 149 |
+
|
| 150 |
+
# Iteratively limit by distance to other circles, allowing constraints to propagate
|
| 151 |
+
for _ in range(300): # Iterate to ensure convergence
|
| 152 |
+
changes_made = False
|
| 153 |
+
for i in range(n):
|
| 154 |
+
for j in range(i + 1, n):
|
| 155 |
+
dist = np.linalg.norm(centers[i] - centers[j])
|
| 156 |
+
|
| 157 |
+
# If current radii cause overlap
|
| 158 |
+
if radii[i] + radii[j] > dist:
|
| 159 |
+
sum_r = radii[i] + radii[j]
|
| 160 |
+
if sum_r > 1e-9: # Avoid division by zero for coincident centers
|
| 161 |
+
# Scale both radii proportionally to resolve overlap
|
| 162 |
+
scale = dist / sum_r
|
| 163 |
+
ri_new = radii[i] * scale
|
| 164 |
+
rj_new = radii[j] * scale
|
| 165 |
+
|
| 166 |
+
# Check for significant change to set the flag
|
| 167 |
+
if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9:
|
| 168 |
+
radii[i] = ri_new
|
| 169 |
+
radii[j] = rj_new
|
| 170 |
+
changes_made = True
|
| 171 |
+
if not changes_made:
|
| 172 |
+
break # Exit early if the configuration is stable
|
| 173 |
+
|
| 174 |
+
return radii
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
# EVOLVE-BLOCK-END
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
# This part remains fixed (not evolved)
|
| 181 |
+
def run_packing():
|
| 182 |
+
"""Run the circle packing constructor for n=26"""
|
| 183 |
+
centers, radii = construct_packing()
|
| 184 |
+
# Calculate the sum of radii
|
| 185 |
+
sum_radii = np.sum(radii)
|
| 186 |
+
return centers, radii, sum_radii
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/correct.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"correct": true,
|
| 3 |
+
"error": null
|
| 4 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/job_log.err
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning:
|
| 2 |
+
|
| 3 |
+
All support for the `google.generativeai` package has ended. It will no longer be receiving
|
| 4 |
+
updates or bug fixes. Please switch to the `google.genai` package as soon as possible.
|
| 5 |
+
See README for more details:
|
| 6 |
+
|
| 7 |
+
https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md
|
| 8 |
+
|
| 9 |
+
import google.generativeai as genai # type: ignore[import-not-found]
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/job_log.out
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/main.py
|
| 2 |
+
Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/results
|
| 3 |
+
Run 1/1 completed in 1.75 seconds
|
| 4 |
+
Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/extra.npz
|
| 5 |
+
Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/packing_viz.png
|
| 6 |
+
Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/correct.json
|
| 7 |
+
Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/metrics.json
|
| 8 |
+
Evaluation and Validation completed successfully.
|
| 9 |
+
Metrics:
|
| 10 |
+
combined_score: 1.9808569554223658
|
| 11 |
+
public: {'centers_str': ' centers[0] = (0.0916, 0.0983)\n centers[1] = (0.2732, 0.0707)\n centers[2] = (0.5267, 0.0707)\n centers[3] = (0.7077, 0.0983)\n centers[4] = (0.9009, 0.1000)\n centers[5] = (0.0916, 0.3016)\n centers[6] = (0.2729, 0.3271)\n centers[7] = (0.5271, 0.3271)\n centers[8] = (0.7077, 0.3016)\n centers[9] = (0.9009, 0.3000)\n centers[10] = (0.0991, 0.5008)\n centers[11] = (0.2984, 0.5077)\n centers[12] = (0.5016, 0.5077)\n centers[13] = (0.7008, 0.5008)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.1000, 0.7001)\n centers[16] = (0.3000, 0.7009)\n centers[17] = (0.5000, 0.7009)\n centers[18] = (0.7000, 0.7001)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1000, 0.9000)\n centers[21] = (0.3000, 0.9001)\n centers[22] = (0.5000, 0.9001)\n centers[23] = (0.7000, 0.9000)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.1999)', 'num_circles': 26}
|
| 12 |
+
private: {'reported_sum_of_radii': 1.9808569554223658}
|
| 13 |
+
visualization_path: <string_too_long_to_display>
|
| 14 |
+
execution_time_mean: 1.751810641027987
|
| 15 |
+
execution_time_std: 0.0
|
| 16 |
+
num_valid_runs: 1
|
| 17 |
+
num_invalid_runs: 0
|
| 18 |
+
all_validation_errors: []
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/metrics.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"combined_score": 1.9808569554223658,
|
| 3 |
+
"public": {
|
| 4 |
+
"centers_str": " centers[0] = (0.0916, 0.0983)\n centers[1] = (0.2732, 0.0707)\n centers[2] = (0.5267, 0.0707)\n centers[3] = (0.7077, 0.0983)\n centers[4] = (0.9009, 0.1000)\n centers[5] = (0.0916, 0.3016)\n centers[6] = (0.2729, 0.3271)\n centers[7] = (0.5271, 0.3271)\n centers[8] = (0.7077, 0.3016)\n centers[9] = (0.9009, 0.3000)\n centers[10] = (0.0991, 0.5008)\n centers[11] = (0.2984, 0.5077)\n centers[12] = (0.5016, 0.5077)\n centers[13] = (0.7008, 0.5008)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.1000, 0.7001)\n centers[16] = (0.3000, 0.7009)\n centers[17] = (0.5000, 0.7009)\n centers[18] = (0.7000, 0.7001)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1000, 0.9000)\n centers[21] = (0.3000, 0.9001)\n centers[22] = (0.5000, 0.9001)\n centers[23] = (0.7000, 0.9000)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.1999)",
|
| 5 |
+
"num_circles": 26
|
| 6 |
+
},
|
| 7 |
+
"private": {
|
| 8 |
+
"reported_sum_of_radii": 1.9808569554223658
|
| 9 |
+
},
|
| 10 |
+
"visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/packing_viz.png",
|
| 11 |
+
"execution_time_mean": 1.751810641027987,
|
| 12 |
+
"execution_time_std": 0.0,
|
| 13 |
+
"num_valid_runs": 1,
|
| 14 |
+
"num_invalid_runs": 0,
|
| 15 |
+
"all_validation_errors": []
|
| 16 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/search_replace.txt
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Based on my analysis of the visualization and the code's history, the current packing is stuck in a suboptimal, grid-like local minimum. The relaxation process is not aggressive enough to break this structure, and it lacks a final polishing stage to maximize density. My proposed changes aim to rectify this by reverting to a more powerful three-stage relaxation process that has proven successful in prior versions.
|
| 2 |
+
|
| 3 |
+
### Change 1: Strengthen Relaxation Stages
|
| 4 |
+
|
| 5 |
+
<NAME>
|
| 6 |
+
strengthen_relaxation_stages
|
| 7 |
+
</NAME>
|
| 8 |
+
|
| 9 |
+
<DESCRIPTION>
|
| 10 |
+
The visualization clearly shows the upper half of the packing is still in a grid-like configuration, indicating the relaxation process is too weak. To break out of this local minimum, I'm strengthening both the "Exploration" and "Refinement" stages. I'm increasing the exploration iterations to 300 and its repulsion strength to 0.025. This provides more energy to "shake" the circles out of their initial grid. Concurrently, I'm increasing the refinement repulsion strength to 0.01. This helps compact the circles more effectively after the more chaotic exploration phase, ensuring they settle into a denser arrangement. These parameter changes are adopted from a previously high-performing configuration.
|
| 11 |
+
</DESCRIPTION>
|
| 12 |
+
|
| 13 |
+
<DIFF>
|
| 14 |
+
<<<<<<< SEARCH
|
| 15 |
+
# Stage 1: High-Energy Exploration
|
| 16 |
+
# This stage uses strong forces and a large step size to quickly move circles
|
| 17 |
+
# out of the initial grid structure and explore new arrangements.
|
| 18 |
+
exploration_iters = 250
|
| 19 |
+
exploration_step_size = 0.003
|
| 20 |
+
exploration_repulsion_strength = 0.02
|
| 21 |
+
=======
|
| 22 |
+
# Stage 1: High-Energy Exploration
|
| 23 |
+
# This stage uses strong forces and a large step size to quickly move circles
|
| 24 |
+
# out of the initial grid structure and explore new arrangements.
|
| 25 |
+
exploration_iters = 300
|
| 26 |
+
exploration_step_size = 0.003
|
| 27 |
+
exploration_repulsion_strength = 0.025
|
| 28 |
+
>>>>>>> REPLACE
|
| 29 |
+
</DIFF>
|
| 30 |
+
<DIFF>
|
| 31 |
+
<<<<<<< SEARCH
|
| 32 |
+
# Stage 2: Low-Energy Refinement
|
| 33 |
+
# This stage uses more iterations with weaker forces and a smaller step size
|
| 34 |
+
# to settle the circles into a dense, stable local optimum.
|
| 35 |
+
refinement_iters = 500
|
| 36 |
+
refinement_step_size = 0.0005
|
| 37 |
+
refinement_repulsion_strength = 0.008
|
| 38 |
+
=======
|
| 39 |
+
# Stage 2: Low-Energy Refinement
|
| 40 |
+
# This stage uses more iterations with weaker forces and a smaller step size
|
| 41 |
+
# to settle the circles into a dense, stable local optimum.
|
| 42 |
+
refinement_iters = 500
|
| 43 |
+
refinement_step_size = 0.0005
|
| 44 |
+
refinement_repulsion_strength = 0.01
|
| 45 |
+
>>>>>>> REPLACE
|
| 46 |
+
</DIFF>
|
| 47 |
+
|
| 48 |
+
### Change 2: Add Annealing Stage
|
| 49 |
+
|
| 50 |
+
<NAME>
|
| 51 |
+
add_annealing_stage
|
| 52 |
+
</NAME>
|
| 53 |
+
|
| 54 |
+
<DESCRIPTION>
|
| 55 |
+
The visualization shows small but significant gaps between circles, indicating the packing is not fully optimized. To address this, I am re-introducing a third "annealing" or "polishing" stage after refinement. This stage uses a high number of iterations (800) with very weak forces and a small step size. Its purpose is to perform micro-adjustments, nudging circles into a tighter final configuration to close up residual empty space. This three-stage relaxation (shake, settle, polish) is a proven strategy from high-performing parent programs and is essential for achieving maximum density.
|
| 56 |
+
</DESCRIPTION>
|
| 57 |
+
|
| 58 |
+
<DIFF>
|
| 59 |
+
<<<<<<< SEARCH
|
| 60 |
+
centers += refinement_step_size * forces
|
| 61 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 62 |
+
|
| 63 |
+
# 6. Compute maximum valid radii for the refined configuration.
|
| 64 |
+
radii = compute_max_radii(centers)
|
| 65 |
+
=======
|
| 66 |
+
centers += refinement_step_size * forces
|
| 67 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 68 |
+
|
| 69 |
+
# Stage 3: Ultra-Low-Energy Annealing ("Polishing")
|
| 70 |
+
# This stage uses very weak forces and many iterations for final micro-adjustments.
|
| 71 |
+
annealing_iters = 800
|
| 72 |
+
annealing_step_size = 0.0001
|
| 73 |
+
annealing_repulsion_strength = 0.004
|
| 74 |
+
annealing_boundary_strength = 0.02
|
| 75 |
+
annealing_repulsion_threshold = 0.18 # Tighter threshold for final packing
|
| 76 |
+
|
| 77 |
+
for _ in range(annealing_iters):
|
| 78 |
+
forces = np.zeros_like(centers)
|
| 79 |
+
for i in range(n):
|
| 80 |
+
for j in range(i + 1, n):
|
| 81 |
+
vec = centers[i] - centers[j]
|
| 82 |
+
dist = np.linalg.norm(vec)
|
| 83 |
+
if 0 < dist < annealing_repulsion_threshold:
|
| 84 |
+
force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist
|
| 85 |
+
force_vec = force_mag * (vec / dist)
|
| 86 |
+
forces[i] += force_vec
|
| 87 |
+
forces[j] -= force_vec
|
| 88 |
+
for i in range(n):
|
| 89 |
+
x, y = centers[i]
|
| 90 |
+
if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x)
|
| 91 |
+
if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin))
|
| 92 |
+
if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y)
|
| 93 |
+
if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin))
|
| 94 |
+
centers += annealing_step_size * forces
|
| 95 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 96 |
+
|
| 97 |
+
# 6. Compute maximum valid radii for the refined configuration.
|
| 98 |
+
radii = compute_max_radii(centers)
|
| 99 |
+
>>>>>>> REPLACE
|
| 100 |
+
</DIFF>
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/__pycache__/main.cpython-311.pyc
ADDED
|
Binary file (7.34 kB). View file
|
|
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/correct.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"correct": true,
|
| 3 |
+
"error": null
|
| 4 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/job_log.err
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning:
|
| 2 |
+
|
| 3 |
+
All support for the `google.generativeai` package has ended. It will no longer be receiving
|
| 4 |
+
updates or bug fixes. Please switch to the `google.genai` package as soon as possible.
|
| 5 |
+
See README for more details:
|
| 6 |
+
|
| 7 |
+
https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md
|
| 8 |
+
|
| 9 |
+
import google.generativeai as genai # type: ignore[import-not-found]
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/job_log.out
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/main.py
|
| 2 |
+
Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/results
|
| 3 |
+
Run 1/1 completed in 2.19 seconds
|
| 4 |
+
Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/extra.npz
|
| 5 |
+
Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/packing_viz.png
|
| 6 |
+
Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/correct.json
|
| 7 |
+
Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/metrics.json
|
| 8 |
+
Evaluation and Validation completed successfully.
|
| 9 |
+
Metrics:
|
| 10 |
+
combined_score: 1.9605693402727424
|
| 11 |
+
public: {'centers_str': ' centers[0] = (0.0819, 0.1001)\n centers[1] = (0.2718, 0.0571)\n centers[2] = (0.5260, 0.0563)\n centers[3] = (0.7130, 0.1004)\n centers[4] = (0.9077, 0.1000)\n centers[5] = (0.0794, 0.2998)\n centers[6] = (0.2691, 0.3279)\n centers[7] = (0.5285, 0.3284)\n centers[8] = (0.7150, 0.2995)\n centers[9] = (0.9084, 0.3000)\n centers[10] = (0.0991, 0.5005)\n centers[11] = (0.3005, 0.5142)\n centers[12] = (0.4995, 0.5144)\n centers[13] = (0.7005, 0.5005)\n centers[14] = (0.9004, 0.5000)\n centers[15] = (0.1000, 0.7003)\n centers[16] = (0.3000, 0.7064)\n centers[17] = (0.5000, 0.7064)\n centers[18] = (0.7000, 0.7003)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1000, 0.9002)\n centers[21] = (0.3000, 0.9028)\n centers[22] = (0.5000, 0.9028)\n centers[23] = (0.7000, 0.9002)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.3996, 0.1958)', 'num_circles': 26}
|
| 12 |
+
private: {'reported_sum_of_radii': 1.9605693402727424}
|
| 13 |
+
visualization_path: <string_too_long_to_display>
|
| 14 |
+
execution_time_mean: 2.1865705880336463
|
| 15 |
+
execution_time_std: 0.0
|
| 16 |
+
num_valid_runs: 1
|
| 17 |
+
num_invalid_runs: 0
|
| 18 |
+
all_validation_errors: []
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/metrics.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"combined_score": 1.9605693402727424,
|
| 3 |
+
"public": {
|
| 4 |
+
"centers_str": " centers[0] = (0.0819, 0.1001)\n centers[1] = (0.2718, 0.0571)\n centers[2] = (0.5260, 0.0563)\n centers[3] = (0.7130, 0.1004)\n centers[4] = (0.9077, 0.1000)\n centers[5] = (0.0794, 0.2998)\n centers[6] = (0.2691, 0.3279)\n centers[7] = (0.5285, 0.3284)\n centers[8] = (0.7150, 0.2995)\n centers[9] = (0.9084, 0.3000)\n centers[10] = (0.0991, 0.5005)\n centers[11] = (0.3005, 0.5142)\n centers[12] = (0.4995, 0.5144)\n centers[13] = (0.7005, 0.5005)\n centers[14] = (0.9004, 0.5000)\n centers[15] = (0.1000, 0.7003)\n centers[16] = (0.3000, 0.7064)\n centers[17] = (0.5000, 0.7064)\n centers[18] = (0.7000, 0.7003)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1000, 0.9002)\n centers[21] = (0.3000, 0.9028)\n centers[22] = (0.5000, 0.9028)\n centers[23] = (0.7000, 0.9002)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.3996, 0.1958)",
|
| 5 |
+
"num_circles": 26
|
| 6 |
+
},
|
| 7 |
+
"private": {
|
| 8 |
+
"reported_sum_of_radii": 1.9605693402727424
|
| 9 |
+
},
|
| 10 |
+
"visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/packing_viz.png",
|
| 11 |
+
"execution_time_mean": 2.1865705880336463,
|
| 12 |
+
"execution_time_std": 0.0,
|
| 13 |
+
"num_valid_runs": 1,
|
| 14 |
+
"num_invalid_runs": 0,
|
| 15 |
+
"all_validation_errors": []
|
| 16 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/__pycache__/main.cpython-311.pyc
ADDED
|
Binary file (9.37 kB). View file
|
|
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/edit.diff
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
--- a/original.py
|
| 2 |
+
+++ b/original.py
|
| 3 |
+
@@ -1,191 +1,229 @@
|
| 4 |
+
# EVOLVE-BLOCK-START
|
| 5 |
+
"""Constructor-based circle packing for n=26 circles"""
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def _relax_stage(centers, n, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin):
|
| 11 |
+
"""
|
| 12 |
+
Helper function to run a single stage of force-directed relaxation.
|
| 13 |
+
"""
|
| 14 |
+
for _ in range(iters):
|
| 15 |
+
forces = np.zeros_like(centers)
|
| 16 |
+
|
| 17 |
+
# Calculate pairwise forces
|
| 18 |
+
for i in range(n):
|
| 19 |
+
for j in range(i + 1, n):
|
| 20 |
+
vec = centers[i] - centers[j]
|
| 21 |
+
dist = np.linalg.norm(vec)
|
| 22 |
+
if 0 < dist < repulsion_threshold:
|
| 23 |
+
# Repulsion force magnitude decreases linearly with distance, up to a threshold
|
| 24 |
+
force_mag = repulsion_strength * (repulsion_threshold - dist) / dist
|
| 25 |
+
force_vec = force_mag * (vec / dist)
|
| 26 |
+
forces[i] += force_vec
|
| 27 |
+
forces[j] -= force_vec
|
| 28 |
+
|
| 29 |
+
# Calculate boundary forces
|
| 30 |
+
for i in range(n):
|
| 31 |
+
x, y = centers[i]
|
| 32 |
+
# Force pushing away from boundaries if too close
|
| 33 |
+
if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x)
|
| 34 |
+
if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin))
|
| 35 |
+
if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y)
|
| 36 |
+
if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin))
|
| 37 |
+
|
| 38 |
+
# Update centers and clip to stay within the unit square
|
| 39 |
+
centers += step_size * forces
|
| 40 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 41 |
+
return centers
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def construct_packing():
|
| 45 |
+
"""
|
| 46 |
+
Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid
|
| 47 |
+
from an asymmetric void and applying a three-stage (exploration/refinement/annealing)
|
| 48 |
+
force-directed relaxation.
|
| 49 |
+
|
| 50 |
+
Returns:
|
| 51 |
+
Tuple of (centers, radii)
|
| 52 |
+
centers: np.array of shape (26, 2) with (x, y) coordinates
|
| 53 |
+
radii: np.array of shape (26) with radius of each circle
|
| 54 |
+
"""
|
| 55 |
+
n = 26
|
| 56 |
+
centers = np.zeros((n, 2))
|
| 57 |
+
|
| 58 |
+
# 1. Start with the 25 centers of a 5x5 grid.
|
| 59 |
+
x_coords = np.linspace(0.1, 0.9, 5)
|
| 60 |
+
y_coords = np.linspace(0.1, 0.9, 5)
|
| 61 |
+
xx, yy = np.meshgrid(x_coords, y_coords)
|
| 62 |
+
base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T
|
| 63 |
+
|
| 64 |
+
# 2. Define an ASYMMETRIC center for the void.
|
| 65 |
+
# Changed from (0.4, 0.4) to (0.4, 0.2) to break symmetry and achieve better packing.
|
| 66 |
+
void_center = np.array([0.4, 0.2])
|
| 67 |
+
|
| 68 |
+
# 3. Deform the 25 grid points with a Gaussian repulsive push from the void center.
|
| 69 |
+
deformed_centers_25 = np.copy(base_centers_25)
|
| 70 |
+
|
| 71 |
+
- # Increased amplitude to create a larger initial void, allowing more room for exploration.
|
| 72 |
+
- amplitude = 0.06 # Increased from 0.05
|
| 73 |
+
+ # Increased amplitude to create a larger, more chaotic initial state.
|
| 74 |
+
+ amplitude = 0.10 # Increased from 0.06
|
| 75 |
+
sigma = 0.15
|
| 76 |
+
|
| 77 |
+
for i in range(25):
|
| 78 |
+
pos_vector = base_centers_25[i] - void_center
|
| 79 |
+
dist_sq = np.sum(pos_vector**2)
|
| 80 |
+
push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2))
|
| 81 |
+
if np.linalg.norm(pos_vector) > 1e-9:
|
| 82 |
+
direction = pos_vector / np.linalg.norm(pos_vector)
|
| 83 |
+
displacement = direction * push_magnitude
|
| 84 |
+
deformed_centers_25[i] += displacement
|
| 85 |
+
|
| 86 |
+
centers[:25] = deformed_centers_25
|
| 87 |
+
centers[25] = void_center
|
| 88 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 89 |
+
|
| 90 |
+
- # 4. Stage 1: High-Energy Exploration ("Shaking")
|
| 91 |
+
- # Increased iterations and strength to break the grid structure more effectively.
|
| 92 |
+
+ # 4. Stage 1: Vortex Disruption (NEW)
|
| 93 |
+
+ # This new stage applies a rotational force to violently break the grid symmetry,
|
| 94 |
+
+ # helping the system escape the initial ordered local minimum.
|
| 95 |
+
+ vortex_iters = 75
|
| 96 |
+
+ vortex_step_size = 0.002
|
| 97 |
+
+ vortex_center = np.array([0.5, 0.5])
|
| 98 |
+
+ vortex_strength = 0.008
|
| 99 |
+
+ vortex_repulsion_strength = 0.015 # Add repulsion to prevent collapse
|
| 100 |
+
+ vortex_boundary_strength = 0.1
|
| 101 |
+
+ vortex_repulsion_threshold = 0.20
|
| 102 |
+
+ vortex_boundary_margin = 0.04
|
| 103 |
+
+
|
| 104 |
+
+ for _ in range(vortex_iters):
|
| 105 |
+
+ forces = np.zeros_like(centers)
|
| 106 |
+
+ for i in range(n):
|
| 107 |
+
+ # Rotational force
|
| 108 |
+
+ vec_from_center = centers[i] - vortex_center
|
| 109 |
+
+ forces[i] += vortex_strength * np.array([-vec_from_center[1], vec_from_center[0]])
|
| 110 |
+
+ # Repulsion force
|
| 111 |
+
+ for j in range(i + 1, n):
|
| 112 |
+
+ vec = centers[i] - centers[j]
|
| 113 |
+
+ dist = np.linalg.norm(vec)
|
| 114 |
+
+ if 0 < dist < vortex_repulsion_threshold:
|
| 115 |
+
+ force_mag = vortex_repulsion_strength * (vortex_repulsion_threshold - dist) / dist
|
| 116 |
+
+ force_vec = force_mag * (vec / dist)
|
| 117 |
+
+ forces[i] += force_vec
|
| 118 |
+
+ forces[j] -= force_vec
|
| 119 |
+
+ # Boundary forces
|
| 120 |
+
+ for i in range(n):
|
| 121 |
+
+ x, y = centers[i]
|
| 122 |
+
+ if x < vortex_boundary_margin: forces[i, 0] += vortex_boundary_strength * (vortex_boundary_margin - x)
|
| 123 |
+
+ if x > 1 - vortex_boundary_margin: forces[i, 0] -= vortex_boundary_strength * (x - (1 - vortex_boundary_margin))
|
| 124 |
+
+ if y < vortex_boundary_margin: forces[i, 1] += vortex_boundary_strength * (y - (1 - vortex_boundary_margin))
|
| 125 |
+
+ if y > 1 - vortex_boundary_margin: forces[i, 1] -= vortex_boundary_strength * (y - (1 - vortex_boundary_margin))
|
| 126 |
+
+ centers += vortex_step_size * forces
|
| 127 |
+
+ centers = np.clip(centers, 0.0, 1.0)
|
| 128 |
+
+
|
| 129 |
+
+
|
| 130 |
+
+ # 5. Stage 2: High-Energy Exploration ("Shaking")
|
| 131 |
+
+ # This stage now operates on a more chaotic configuration from the vortex.
|
| 132 |
+
exploration_iters = 350 # Increased from 250
|
| 133 |
+
exploration_step_size = 0.003
|
| 134 |
+
exploration_repulsion_strength = 0.025 # Increased from 0.02
|
| 135 |
+
exploration_boundary_strength = 0.1
|
| 136 |
+
exploration_repulsion_threshold = 0.20
|
| 137 |
+
exploration_boundary_margin = 0.04 # Initial broader margin
|
| 138 |
+
|
| 139 |
+
centers = _relax_stage(centers, n, exploration_iters, exploration_step_size,
|
| 140 |
+
exploration_repulsion_strength, exploration_boundary_strength,
|
| 141 |
+
exploration_repulsion_threshold, exploration_boundary_margin)
|
| 142 |
+
|
| 143 |
+
- # 5. Stage 2: Low-Energy Refinement ("Settling")
|
| 144 |
+
+ # 6. Stage 3: Low-Energy Refinement ("Settling")
|
| 145 |
+
# A longer settling period with moderate forces to find a good basin of attraction.
|
| 146 |
+
refinement_iters = 600 # Increased from 400
|
| 147 |
+
refinement_step_size = 0.0005
|
| 148 |
+
refinement_repulsion_strength = 0.01 # Increased from 0.008
|
| 149 |
+
refinement_boundary_strength = 0.04
|
| 150 |
+
refinement_repulsion_threshold = 0.185
|
| 151 |
+
refinement_boundary_margin = 0.02 # Tighter margin for finer packing against boundaries
|
| 152 |
+
|
| 153 |
+
centers = _relax_stage(centers, n, refinement_iters, refinement_step_size,
|
| 154 |
+
refinement_repulsion_strength, refinement_boundary_strength,
|
| 155 |
+
refinement_repulsion_threshold, refinement_boundary_margin)
|
| 156 |
+
|
| 157 |
+
- # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") - NEW STAGE
|
| 158 |
+
+ # 7. Stage 4: Ultra-Low-Energy Annealing ("Polishing")
|
| 159 |
+
# Final micro-adjustments with very weak forces and many iterations for precise packing.
|
| 160 |
+
annealing_iters = 800
|
| 161 |
+
annealing_step_size = 0.0001
|
| 162 |
+
annealing_repulsion_strength = 0.004
|
| 163 |
+
annealing_boundary_strength = 0.02
|
| 164 |
+
annealing_repulsion_threshold = 0.18
|
| 165 |
+
annealing_boundary_margin = 0.01 # Even tighter margin for final precision
|
| 166 |
+
|
| 167 |
+
centers = _relax_stage(centers, n, annealing_iters, annealing_step_size,
|
| 168 |
+
annealing_repulsion_strength, annealing_boundary_strength,
|
| 169 |
+
annealing_repulsion_threshold, annealing_boundary_margin)
|
| 170 |
+
|
| 171 |
+
- # 7. Compute maximum valid radii for the final configuration.
|
| 172 |
+
+ # 8. Compute maximum valid radii for the final configuration.
|
| 173 |
+
radii = compute_max_radii(centers)
|
| 174 |
+
return centers, radii
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
def compute_max_radii(centers):
|
| 178 |
+
"""
|
| 179 |
+
Compute the maximum possible radii for each circle position
|
| 180 |
+
such that they don't overlap and stay within the unit square. This is
|
| 181 |
+
an iterative version that converges to a stable solution.
|
| 182 |
+
|
| 183 |
+
Args:
|
| 184 |
+
centers: np.array of shape (n, 2) with (x, y) coordinates
|
| 185 |
+
|
| 186 |
+
Returns:
|
| 187 |
+
np.array of shape (n) with radius of each circle
|
| 188 |
+
"""
|
| 189 |
+
n = centers.shape[0]
|
| 190 |
+
|
| 191 |
+
# Initialize radii based on distance to the square's boundaries (vectorized for efficiency).
|
| 192 |
+
radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0)
|
| 193 |
+
|
| 194 |
+
# Iteratively resolve overlaps between circles until no more changes occur.
|
| 195 |
+
# A high number of iterations ensures convergence for complex arrangements.
|
| 196 |
+
for _ in range(500):
|
| 197 |
+
changed_in_pass = False
|
| 198 |
+
# Check every pair of circles for overlap
|
| 199 |
+
for i in range(n):
|
| 200 |
+
for j in range(i + 1, n):
|
| 201 |
+
dist = np.linalg.norm(centers[i] - centers[j])
|
| 202 |
+
|
| 203 |
+
# If they overlap (with a small tolerance for floating point math)
|
| 204 |
+
if radii[i] + radii[j] > dist + 1e-12:
|
| 205 |
+
# Scale both radii down proportionally to resolve the overlap.
|
| 206 |
+
sum_r = radii[i] + radii[j]
|
| 207 |
+
if sum_r > 1e-12: # Avoid division by zero if sum_r is effectively zero
|
| 208 |
+
scale = dist / sum_r
|
| 209 |
+
ri_new = radii[i] * scale
|
| 210 |
+
rj_new = radii[j] * scale
|
| 211 |
+
|
| 212 |
+
# Check for significant change before updating to avoid unnecessary iterations
|
| 213 |
+
if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12:
|
| 214 |
+
radii[i] = ri_new
|
| 215 |
+
radii[j] = rj_new
|
| 216 |
+
changed_in_pass = True
|
| 217 |
+
else: # If both radii are already ~0, ensure they are exactly 0
|
| 218 |
+
if radii[i] > 1e-12 or radii[j] > 1e-12: # Only change if not already near zero
|
| 219 |
+
radii[i] = 0
|
| 220 |
+
radii[j] = 0
|
| 221 |
+
changed_in_pass = True
|
| 222 |
+
|
| 223 |
+
# If a full pass resulted in no changes, the packing is stable.
|
| 224 |
+
if not changed_in_pass:
|
| 225 |
+
break
|
| 226 |
+
|
| 227 |
+
return radii
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
# EVOLVE-BLOCK-END
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
# This part remains fixed (not evolved)
|
| 234 |
+
def run_packing():
|
| 235 |
+
"""Run the circle packing constructor for n=26"""
|
| 236 |
+
centers, radii = construct_packing()
|
| 237 |
+
# Calculate the sum of radii
|
| 238 |
+
sum_radii = np.sum(radii)
|
| 239 |
+
return centers, radii, sum_radii
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/main.py
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# EVOLVE-BLOCK-START
|
| 2 |
+
"""Constructor-based circle packing for n=26 circles"""
|
| 3 |
+
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def _relax_stage(centers, n, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin):
|
| 8 |
+
"""
|
| 9 |
+
Helper function to run a single stage of force-directed relaxation.
|
| 10 |
+
"""
|
| 11 |
+
for _ in range(iters):
|
| 12 |
+
forces = np.zeros_like(centers)
|
| 13 |
+
|
| 14 |
+
# Calculate pairwise forces
|
| 15 |
+
for i in range(n):
|
| 16 |
+
for j in range(i + 1, n):
|
| 17 |
+
vec = centers[i] - centers[j]
|
| 18 |
+
dist = np.linalg.norm(vec)
|
| 19 |
+
if 0 < dist < repulsion_threshold:
|
| 20 |
+
# Repulsion force magnitude decreases linearly with distance, up to a threshold
|
| 21 |
+
force_mag = repulsion_strength * (repulsion_threshold - dist) / dist
|
| 22 |
+
force_vec = force_mag * (vec / dist)
|
| 23 |
+
forces[i] += force_vec
|
| 24 |
+
forces[j] -= force_vec
|
| 25 |
+
|
| 26 |
+
# Calculate boundary forces
|
| 27 |
+
for i in range(n):
|
| 28 |
+
x, y = centers[i]
|
| 29 |
+
# Force pushing away from boundaries if too close
|
| 30 |
+
if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x)
|
| 31 |
+
if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin))
|
| 32 |
+
if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y)
|
| 33 |
+
if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin))
|
| 34 |
+
|
| 35 |
+
# Update centers and clip to stay within the unit square
|
| 36 |
+
centers += step_size * forces
|
| 37 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 38 |
+
return centers
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def construct_packing():
|
| 42 |
+
"""
|
| 43 |
+
Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid
|
| 44 |
+
from an asymmetric void and applying a three-stage (exploration/refinement/annealing)
|
| 45 |
+
force-directed relaxation.
|
| 46 |
+
|
| 47 |
+
Returns:
|
| 48 |
+
Tuple of (centers, radii)
|
| 49 |
+
centers: np.array of shape (26, 2) with (x, y) coordinates
|
| 50 |
+
radii: np.array of shape (26) with radius of each circle
|
| 51 |
+
"""
|
| 52 |
+
n = 26
|
| 53 |
+
centers = np.zeros((n, 2))
|
| 54 |
+
|
| 55 |
+
# 1. Start with the 25 centers of a 5x5 grid.
|
| 56 |
+
x_coords = np.linspace(0.1, 0.9, 5)
|
| 57 |
+
y_coords = np.linspace(0.1, 0.9, 5)
|
| 58 |
+
xx, yy = np.meshgrid(x_coords, y_coords)
|
| 59 |
+
base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T
|
| 60 |
+
|
| 61 |
+
# 2. Define an ASYMMETRIC center for the void.
|
| 62 |
+
# Changed from (0.4, 0.4) to (0.4, 0.2) to break symmetry and achieve better packing.
|
| 63 |
+
void_center = np.array([0.4, 0.2])
|
| 64 |
+
|
| 65 |
+
# 3. Deform the 25 grid points with a Gaussian repulsive push from the void center.
|
| 66 |
+
deformed_centers_25 = np.copy(base_centers_25)
|
| 67 |
+
|
| 68 |
+
# Increased amplitude to create a larger, more chaotic initial state.
|
| 69 |
+
amplitude = 0.10 # Increased from 0.06
|
| 70 |
+
sigma = 0.15
|
| 71 |
+
|
| 72 |
+
for i in range(25):
|
| 73 |
+
pos_vector = base_centers_25[i] - void_center
|
| 74 |
+
dist_sq = np.sum(pos_vector**2)
|
| 75 |
+
push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2))
|
| 76 |
+
if np.linalg.norm(pos_vector) > 1e-9:
|
| 77 |
+
direction = pos_vector / np.linalg.norm(pos_vector)
|
| 78 |
+
displacement = direction * push_magnitude
|
| 79 |
+
deformed_centers_25[i] += displacement
|
| 80 |
+
|
| 81 |
+
centers[:25] = deformed_centers_25
|
| 82 |
+
centers[25] = void_center
|
| 83 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 84 |
+
|
| 85 |
+
# 4. Stage 1: Vortex Disruption (NEW)
|
| 86 |
+
# This new stage applies a rotational force to violently break the grid symmetry,
|
| 87 |
+
# helping the system escape the initial ordered local minimum.
|
| 88 |
+
vortex_iters = 75
|
| 89 |
+
vortex_step_size = 0.002
|
| 90 |
+
vortex_center = np.array([0.5, 0.5])
|
| 91 |
+
vortex_strength = 0.008
|
| 92 |
+
vortex_repulsion_strength = 0.015 # Add repulsion to prevent collapse
|
| 93 |
+
vortex_boundary_strength = 0.1
|
| 94 |
+
vortex_repulsion_threshold = 0.20
|
| 95 |
+
vortex_boundary_margin = 0.04
|
| 96 |
+
|
| 97 |
+
for _ in range(vortex_iters):
|
| 98 |
+
forces = np.zeros_like(centers)
|
| 99 |
+
for i in range(n):
|
| 100 |
+
# Rotational force
|
| 101 |
+
vec_from_center = centers[i] - vortex_center
|
| 102 |
+
forces[i] += vortex_strength * np.array([-vec_from_center[1], vec_from_center[0]])
|
| 103 |
+
# Repulsion force
|
| 104 |
+
for j in range(i + 1, n):
|
| 105 |
+
vec = centers[i] - centers[j]
|
| 106 |
+
dist = np.linalg.norm(vec)
|
| 107 |
+
if 0 < dist < vortex_repulsion_threshold:
|
| 108 |
+
force_mag = vortex_repulsion_strength * (vortex_repulsion_threshold - dist) / dist
|
| 109 |
+
force_vec = force_mag * (vec / dist)
|
| 110 |
+
forces[i] += force_vec
|
| 111 |
+
forces[j] -= force_vec
|
| 112 |
+
# Boundary forces
|
| 113 |
+
for i in range(n):
|
| 114 |
+
x, y = centers[i]
|
| 115 |
+
if x < vortex_boundary_margin: forces[i, 0] += vortex_boundary_strength * (vortex_boundary_margin - x)
|
| 116 |
+
if x > 1 - vortex_boundary_margin: forces[i, 0] -= vortex_boundary_strength * (x - (1 - vortex_boundary_margin))
|
| 117 |
+
if y < vortex_boundary_margin: forces[i, 1] += vortex_boundary_strength * (y - (1 - vortex_boundary_margin))
|
| 118 |
+
if y > 1 - vortex_boundary_margin: forces[i, 1] -= vortex_boundary_strength * (y - (1 - vortex_boundary_margin))
|
| 119 |
+
centers += vortex_step_size * forces
|
| 120 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
# 5. Stage 2: High-Energy Exploration ("Shaking")
|
| 124 |
+
# This stage now operates on a more chaotic configuration from the vortex.
|
| 125 |
+
exploration_iters = 350 # Increased from 250
|
| 126 |
+
exploration_step_size = 0.003
|
| 127 |
+
exploration_repulsion_strength = 0.025 # Increased from 0.02
|
| 128 |
+
exploration_boundary_strength = 0.1
|
| 129 |
+
exploration_repulsion_threshold = 0.20
|
| 130 |
+
exploration_boundary_margin = 0.04 # Initial broader margin
|
| 131 |
+
|
| 132 |
+
centers = _relax_stage(centers, n, exploration_iters, exploration_step_size,
|
| 133 |
+
exploration_repulsion_strength, exploration_boundary_strength,
|
| 134 |
+
exploration_repulsion_threshold, exploration_boundary_margin)
|
| 135 |
+
|
| 136 |
+
# 6. Stage 3: Low-Energy Refinement ("Settling")
|
| 137 |
+
# A longer settling period with moderate forces to find a good basin of attraction.
|
| 138 |
+
refinement_iters = 600 # Increased from 400
|
| 139 |
+
refinement_step_size = 0.0005
|
| 140 |
+
refinement_repulsion_strength = 0.01 # Increased from 0.008
|
| 141 |
+
refinement_boundary_strength = 0.04
|
| 142 |
+
refinement_repulsion_threshold = 0.185
|
| 143 |
+
refinement_boundary_margin = 0.02 # Tighter margin for finer packing against boundaries
|
| 144 |
+
|
| 145 |
+
centers = _relax_stage(centers, n, refinement_iters, refinement_step_size,
|
| 146 |
+
refinement_repulsion_strength, refinement_boundary_strength,
|
| 147 |
+
refinement_repulsion_threshold, refinement_boundary_margin)
|
| 148 |
+
|
| 149 |
+
# 7. Stage 4: Ultra-Low-Energy Annealing ("Polishing")
|
| 150 |
+
# Final micro-adjustments with very weak forces and many iterations for precise packing.
|
| 151 |
+
annealing_iters = 800
|
| 152 |
+
annealing_step_size = 0.0001
|
| 153 |
+
annealing_repulsion_strength = 0.004
|
| 154 |
+
annealing_boundary_strength = 0.02
|
| 155 |
+
annealing_repulsion_threshold = 0.18
|
| 156 |
+
annealing_boundary_margin = 0.01 # Even tighter margin for final precision
|
| 157 |
+
|
| 158 |
+
centers = _relax_stage(centers, n, annealing_iters, annealing_step_size,
|
| 159 |
+
annealing_repulsion_strength, annealing_boundary_strength,
|
| 160 |
+
annealing_repulsion_threshold, annealing_boundary_margin)
|
| 161 |
+
|
| 162 |
+
# 8. Compute maximum valid radii for the final configuration.
|
| 163 |
+
radii = compute_max_radii(centers)
|
| 164 |
+
return centers, radii
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def compute_max_radii(centers):
|
| 168 |
+
"""
|
| 169 |
+
Compute the maximum possible radii for each circle position
|
| 170 |
+
such that they don't overlap and stay within the unit square. This is
|
| 171 |
+
an iterative version that converges to a stable solution.
|
| 172 |
+
|
| 173 |
+
Args:
|
| 174 |
+
centers: np.array of shape (n, 2) with (x, y) coordinates
|
| 175 |
+
|
| 176 |
+
Returns:
|
| 177 |
+
np.array of shape (n) with radius of each circle
|
| 178 |
+
"""
|
| 179 |
+
n = centers.shape[0]
|
| 180 |
+
|
| 181 |
+
# Initialize radii based on distance to the square's boundaries (vectorized for efficiency).
|
| 182 |
+
radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0)
|
| 183 |
+
|
| 184 |
+
# Iteratively resolve overlaps between circles until no more changes occur.
|
| 185 |
+
# A high number of iterations ensures convergence for complex arrangements.
|
| 186 |
+
for _ in range(500):
|
| 187 |
+
changed_in_pass = False
|
| 188 |
+
# Check every pair of circles for overlap
|
| 189 |
+
for i in range(n):
|
| 190 |
+
for j in range(i + 1, n):
|
| 191 |
+
dist = np.linalg.norm(centers[i] - centers[j])
|
| 192 |
+
|
| 193 |
+
# If they overlap (with a small tolerance for floating point math)
|
| 194 |
+
if radii[i] + radii[j] > dist + 1e-12:
|
| 195 |
+
# Scale both radii down proportionally to resolve the overlap.
|
| 196 |
+
sum_r = radii[i] + radii[j]
|
| 197 |
+
if sum_r > 1e-12: # Avoid division by zero if sum_r is effectively zero
|
| 198 |
+
scale = dist / sum_r
|
| 199 |
+
ri_new = radii[i] * scale
|
| 200 |
+
rj_new = radii[j] * scale
|
| 201 |
+
|
| 202 |
+
# Check for significant change before updating to avoid unnecessary iterations
|
| 203 |
+
if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12:
|
| 204 |
+
radii[i] = ri_new
|
| 205 |
+
radii[j] = rj_new
|
| 206 |
+
changed_in_pass = True
|
| 207 |
+
else: # If both radii are already ~0, ensure they are exactly 0
|
| 208 |
+
if radii[i] > 1e-12 or radii[j] > 1e-12: # Only change if not already near zero
|
| 209 |
+
radii[i] = 0
|
| 210 |
+
radii[j] = 0
|
| 211 |
+
changed_in_pass = True
|
| 212 |
+
|
| 213 |
+
# If a full pass resulted in no changes, the packing is stable.
|
| 214 |
+
if not changed_in_pass:
|
| 215 |
+
break
|
| 216 |
+
|
| 217 |
+
return radii
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
# EVOLVE-BLOCK-END
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
# This part remains fixed (not evolved)
|
| 224 |
+
def run_packing():
|
| 225 |
+
"""Run the circle packing constructor for n=26"""
|
| 226 |
+
centers, radii = construct_packing()
|
| 227 |
+
# Calculate the sum of radii
|
| 228 |
+
sum_radii = np.sum(radii)
|
| 229 |
+
return centers, radii, sum_radii
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/original.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# EVOLVE-BLOCK-START
|
| 2 |
+
"""Constructor-based circle packing for n=26 circles"""
|
| 3 |
+
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def _relax_stage(centers, n, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin):
|
| 8 |
+
"""
|
| 9 |
+
Helper function to run a single stage of force-directed relaxation.
|
| 10 |
+
"""
|
| 11 |
+
for _ in range(iters):
|
| 12 |
+
forces = np.zeros_like(centers)
|
| 13 |
+
|
| 14 |
+
# Calculate pairwise forces
|
| 15 |
+
for i in range(n):
|
| 16 |
+
for j in range(i + 1, n):
|
| 17 |
+
vec = centers[i] - centers[j]
|
| 18 |
+
dist = np.linalg.norm(vec)
|
| 19 |
+
if 0 < dist < repulsion_threshold:
|
| 20 |
+
# Repulsion force magnitude decreases linearly with distance, up to a threshold
|
| 21 |
+
force_mag = repulsion_strength * (repulsion_threshold - dist) / dist
|
| 22 |
+
force_vec = force_mag * (vec / dist)
|
| 23 |
+
forces[i] += force_vec
|
| 24 |
+
forces[j] -= force_vec
|
| 25 |
+
|
| 26 |
+
# Calculate boundary forces
|
| 27 |
+
for i in range(n):
|
| 28 |
+
x, y = centers[i]
|
| 29 |
+
# Force pushing away from boundaries if too close
|
| 30 |
+
if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x)
|
| 31 |
+
if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin))
|
| 32 |
+
if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y)
|
| 33 |
+
if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin))
|
| 34 |
+
|
| 35 |
+
# Update centers and clip to stay within the unit square
|
| 36 |
+
centers += step_size * forces
|
| 37 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 38 |
+
return centers
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def construct_packing():
|
| 42 |
+
"""
|
| 43 |
+
Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid
|
| 44 |
+
from an asymmetric void and applying a three-stage (exploration/refinement/annealing)
|
| 45 |
+
force-directed relaxation.
|
| 46 |
+
|
| 47 |
+
Returns:
|
| 48 |
+
Tuple of (centers, radii)
|
| 49 |
+
centers: np.array of shape (26, 2) with (x, y) coordinates
|
| 50 |
+
radii: np.array of shape (26) with radius of each circle
|
| 51 |
+
"""
|
| 52 |
+
n = 26
|
| 53 |
+
centers = np.zeros((n, 2))
|
| 54 |
+
|
| 55 |
+
# 1. Start with the 25 centers of a 5x5 grid.
|
| 56 |
+
x_coords = np.linspace(0.1, 0.9, 5)
|
| 57 |
+
y_coords = np.linspace(0.1, 0.9, 5)
|
| 58 |
+
xx, yy = np.meshgrid(x_coords, y_coords)
|
| 59 |
+
base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T
|
| 60 |
+
|
| 61 |
+
# 2. Define an ASYMMETRIC center for the void.
|
| 62 |
+
# Changed from (0.4, 0.4) to (0.4, 0.2) to break symmetry and achieve better packing.
|
| 63 |
+
void_center = np.array([0.4, 0.2])
|
| 64 |
+
|
| 65 |
+
# 3. Deform the 25 grid points with a Gaussian repulsive push from the void center.
|
| 66 |
+
deformed_centers_25 = np.copy(base_centers_25)
|
| 67 |
+
|
| 68 |
+
# Increased amplitude to create a larger initial void, allowing more room for exploration.
|
| 69 |
+
amplitude = 0.06 # Increased from 0.05
|
| 70 |
+
sigma = 0.15
|
| 71 |
+
|
| 72 |
+
for i in range(25):
|
| 73 |
+
pos_vector = base_centers_25[i] - void_center
|
| 74 |
+
dist_sq = np.sum(pos_vector**2)
|
| 75 |
+
push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2))
|
| 76 |
+
if np.linalg.norm(pos_vector) > 1e-9:
|
| 77 |
+
direction = pos_vector / np.linalg.norm(pos_vector)
|
| 78 |
+
displacement = direction * push_magnitude
|
| 79 |
+
deformed_centers_25[i] += displacement
|
| 80 |
+
|
| 81 |
+
centers[:25] = deformed_centers_25
|
| 82 |
+
centers[25] = void_center
|
| 83 |
+
centers = np.clip(centers, 0.0, 1.0)
|
| 84 |
+
|
| 85 |
+
# 4. Stage 1: High-Energy Exploration ("Shaking")
|
| 86 |
+
# Increased iterations and strength to break the grid structure more effectively.
|
| 87 |
+
exploration_iters = 350 # Increased from 250
|
| 88 |
+
exploration_step_size = 0.003
|
| 89 |
+
exploration_repulsion_strength = 0.025 # Increased from 0.02
|
| 90 |
+
exploration_boundary_strength = 0.1
|
| 91 |
+
exploration_repulsion_threshold = 0.20
|
| 92 |
+
exploration_boundary_margin = 0.04 # Initial broader margin
|
| 93 |
+
|
| 94 |
+
centers = _relax_stage(centers, n, exploration_iters, exploration_step_size,
|
| 95 |
+
exploration_repulsion_strength, exploration_boundary_strength,
|
| 96 |
+
exploration_repulsion_threshold, exploration_boundary_margin)
|
| 97 |
+
|
| 98 |
+
# 5. Stage 2: Low-Energy Refinement ("Settling")
|
| 99 |
+
# A longer settling period with moderate forces to find a good basin of attraction.
|
| 100 |
+
refinement_iters = 600 # Increased from 400
|
| 101 |
+
refinement_step_size = 0.0005
|
| 102 |
+
refinement_repulsion_strength = 0.01 # Increased from 0.008
|
| 103 |
+
refinement_boundary_strength = 0.04
|
| 104 |
+
refinement_repulsion_threshold = 0.185
|
| 105 |
+
refinement_boundary_margin = 0.02 # Tighter margin for finer packing against boundaries
|
| 106 |
+
|
| 107 |
+
centers = _relax_stage(centers, n, refinement_iters, refinement_step_size,
|
| 108 |
+
refinement_repulsion_strength, refinement_boundary_strength,
|
| 109 |
+
refinement_repulsion_threshold, refinement_boundary_margin)
|
| 110 |
+
|
| 111 |
+
# 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") - NEW STAGE
|
| 112 |
+
# Final micro-adjustments with very weak forces and many iterations for precise packing.
|
| 113 |
+
annealing_iters = 800
|
| 114 |
+
annealing_step_size = 0.0001
|
| 115 |
+
annealing_repulsion_strength = 0.004
|
| 116 |
+
annealing_boundary_strength = 0.02
|
| 117 |
+
annealing_repulsion_threshold = 0.18
|
| 118 |
+
annealing_boundary_margin = 0.01 # Even tighter margin for final precision
|
| 119 |
+
|
| 120 |
+
centers = _relax_stage(centers, n, annealing_iters, annealing_step_size,
|
| 121 |
+
annealing_repulsion_strength, annealing_boundary_strength,
|
| 122 |
+
annealing_repulsion_threshold, annealing_boundary_margin)
|
| 123 |
+
|
| 124 |
+
# 7. Compute maximum valid radii for the final configuration.
|
| 125 |
+
radii = compute_max_radii(centers)
|
| 126 |
+
return centers, radii
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
def compute_max_radii(centers):
|
| 130 |
+
"""
|
| 131 |
+
Compute the maximum possible radii for each circle position
|
| 132 |
+
such that they don't overlap and stay within the unit square. This is
|
| 133 |
+
an iterative version that converges to a stable solution.
|
| 134 |
+
|
| 135 |
+
Args:
|
| 136 |
+
centers: np.array of shape (n, 2) with (x, y) coordinates
|
| 137 |
+
|
| 138 |
+
Returns:
|
| 139 |
+
np.array of shape (n) with radius of each circle
|
| 140 |
+
"""
|
| 141 |
+
n = centers.shape[0]
|
| 142 |
+
|
| 143 |
+
# Initialize radii based on distance to the square's boundaries (vectorized for efficiency).
|
| 144 |
+
radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0)
|
| 145 |
+
|
| 146 |
+
# Iteratively resolve overlaps between circles until no more changes occur.
|
| 147 |
+
# A high number of iterations ensures convergence for complex arrangements.
|
| 148 |
+
for _ in range(500):
|
| 149 |
+
changed_in_pass = False
|
| 150 |
+
# Check every pair of circles for overlap
|
| 151 |
+
for i in range(n):
|
| 152 |
+
for j in range(i + 1, n):
|
| 153 |
+
dist = np.linalg.norm(centers[i] - centers[j])
|
| 154 |
+
|
| 155 |
+
# If they overlap (with a small tolerance for floating point math)
|
| 156 |
+
if radii[i] + radii[j] > dist + 1e-12:
|
| 157 |
+
# Scale both radii down proportionally to resolve the overlap.
|
| 158 |
+
sum_r = radii[i] + radii[j]
|
| 159 |
+
if sum_r > 1e-12: # Avoid division by zero if sum_r is effectively zero
|
| 160 |
+
scale = dist / sum_r
|
| 161 |
+
ri_new = radii[i] * scale
|
| 162 |
+
rj_new = radii[j] * scale
|
| 163 |
+
|
| 164 |
+
# Check for significant change before updating to avoid unnecessary iterations
|
| 165 |
+
if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12:
|
| 166 |
+
radii[i] = ri_new
|
| 167 |
+
radii[j] = rj_new
|
| 168 |
+
changed_in_pass = True
|
| 169 |
+
else: # If both radii are already ~0, ensure they are exactly 0
|
| 170 |
+
if radii[i] > 1e-12 or radii[j] > 1e-12: # Only change if not already near zero
|
| 171 |
+
radii[i] = 0
|
| 172 |
+
radii[j] = 0
|
| 173 |
+
changed_in_pass = True
|
| 174 |
+
|
| 175 |
+
# If a full pass resulted in no changes, the packing is stable.
|
| 176 |
+
if not changed_in_pass:
|
| 177 |
+
break
|
| 178 |
+
|
| 179 |
+
return radii
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
# EVOLVE-BLOCK-END
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
# This part remains fixed (not evolved)
|
| 186 |
+
def run_packing():
|
| 187 |
+
"""Run the circle packing constructor for n=26"""
|
| 188 |
+
centers, radii = construct_packing()
|
| 189 |
+
# Calculate the sum of radii
|
| 190 |
+
sum_radii = np.sum(radii)
|
| 191 |
+
return centers, radii, sum_radii
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/correct.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"correct": true,
|
| 3 |
+
"error": null
|
| 4 |
+
}
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/job_log.err
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning:
|
| 2 |
+
|
| 3 |
+
All support for the `google.generativeai` package has ended. It will no longer be receiving
|
| 4 |
+
updates or bug fixes. Please switch to the `google.genai` package as soon as possible.
|
| 5 |
+
See README for more details:
|
| 6 |
+
|
| 7 |
+
https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md
|
| 8 |
+
|
| 9 |
+
import google.generativeai as genai # type: ignore[import-not-found]
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/job_log.out
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/main.py
|
| 2 |
+
Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/results
|
| 3 |
+
Run 1/1 completed in 2.24 seconds
|
| 4 |
+
Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/extra.npz
|
| 5 |
+
Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/packing_viz.png
|
| 6 |
+
Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/correct.json
|
| 7 |
+
Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/metrics.json
|
| 8 |
+
Evaluation and Validation completed successfully.
|
| 9 |
+
Metrics:
|
| 10 |
+
combined_score: 1.9785014833887988
|
| 11 |
+
public: {'centers_str': ' centers[0] = (0.0861, 0.0971)\n centers[1] = (0.2593, 0.0533)\n centers[2] = (0.5416, 0.0536)\n centers[3] = (0.7134, 0.0979)\n centers[4] = (0.9024, 0.1004)\n centers[5] = (0.0856, 0.3017)\n centers[6] = (0.2581, 0.3416)\n centers[7] = (0.5421, 0.3420)\n centers[8] = (0.7134, 0.3024)\n centers[9] = (0.9021, 0.3005)\n centers[10] = (0.0986, 0.5008)\n centers[11] = (0.2978, 0.5129)\n centers[12] = (0.5022, 0.5132)\n centers[13] = (0.7013, 0.5015)\n centers[14] = (0.9002, 0.5005)\n centers[15] = (0.0997, 0.6997)\n centers[16] = (0.2997, 0.7015)\n centers[17] = (0.4998, 0.7018)\n centers[18] = (0.6998, 0.7004)\n centers[19] = (0.8998, 0.7005)\n centers[20] = (0.0995, 0.8995)\n centers[21] = (0.2995, 0.8999)\n centers[22] = (0.4995, 0.9001)\n centers[23] = (0.6995, 0.9003)\n centers[24] = (0.8995, 0.9005)\n centers[25] = (0.4004, 0.1999)', 'num_circles': 26}
|
| 12 |
+
private: {'reported_sum_of_radii': 1.9785014833887988}
|
| 13 |
+
visualization_path: <string_too_long_to_display>
|
| 14 |
+
execution_time_mean: 2.236732121091336
|
| 15 |
+
execution_time_std: 0.0
|
| 16 |
+
num_valid_runs: 1
|
| 17 |
+
num_invalid_runs: 0
|
| 18 |
+
all_validation_errors: []
|
examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/metrics.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"combined_score": 1.9785014833887988,
|
| 3 |
+
"public": {
|
| 4 |
+
"centers_str": " centers[0] = (0.0861, 0.0971)\n centers[1] = (0.2593, 0.0533)\n centers[2] = (0.5416, 0.0536)\n centers[3] = (0.7134, 0.0979)\n centers[4] = (0.9024, 0.1004)\n centers[5] = (0.0856, 0.3017)\n centers[6] = (0.2581, 0.3416)\n centers[7] = (0.5421, 0.3420)\n centers[8] = (0.7134, 0.3024)\n centers[9] = (0.9021, 0.3005)\n centers[10] = (0.0986, 0.5008)\n centers[11] = (0.2978, 0.5129)\n centers[12] = (0.5022, 0.5132)\n centers[13] = (0.7013, 0.5015)\n centers[14] = (0.9002, 0.5005)\n centers[15] = (0.0997, 0.6997)\n centers[16] = (0.2997, 0.7015)\n centers[17] = (0.4998, 0.7018)\n centers[18] = (0.6998, 0.7004)\n centers[19] = (0.8998, 0.7005)\n centers[20] = (0.0995, 0.8995)\n centers[21] = (0.2995, 0.8999)\n centers[22] = (0.4995, 0.9001)\n centers[23] = (0.6995, 0.9003)\n centers[24] = (0.8995, 0.9005)\n centers[25] = (0.4004, 0.1999)",
|
| 5 |
+
"num_circles": 26
|
| 6 |
+
},
|
| 7 |
+
"private": {
|
| 8 |
+
"reported_sum_of_radii": 1.9785014833887988
|
| 9 |
+
},
|
| 10 |
+
"visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/packing_viz.png",
|
| 11 |
+
"execution_time_mean": 2.236732121091336,
|
| 12 |
+
"execution_time_std": 0.0,
|
| 13 |
+
"num_valid_runs": 1,
|
| 14 |
+
"num_invalid_runs": 0,
|
| 15 |
+
"all_validation_errors": []
|
| 16 |
+
}
|