diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8c994ede4e7eb161838fbbeba24c4b83869b20b5 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..cb50bcd54c54f5e52f4c96187e826181eacbc530 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/edit.diff @@ -0,0 +1,415 @@ +--- a/original.py ++++ b/original.py +@@ -1,184 +1,262 @@ + # EVOLVE-BLOCK-START +-""" +-Constructor-based circle packing for n=26 circles using a hybrid approach: +-a force-directed pre-relaxation followed by an advanced Simulated Annealing search. +-""" +- + import numpy as np +- +-def compute_max_radii(centers): +- """ +- Compute the maximum possible radii for each circle position such that they +- don't overlap and stay within the unit square. This is an iterative version +- that converges to a stable solution. ++import math ++ ++def compute_max_radii(centers, max_iterations=750): ++ """ ++ Compute the maximum possible radii for each circle position ++ such that they don't overlap and stay within the unit square. This is ++ an iterative version that converges to a stable solution. + """ + n = centers.shape[0] +- # Initialize radii based on distance to boundaries (vectorized) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) +- +- # Iteratively resolve overlaps until convergence +- for _ in range(500): ++ for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True +- elif radii[i] > 0 or radii[j] > 0: +- radii[i], radii[j] = 0, 0 +- changes_made = True + if not changes_made: + break + return radii + +-def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): +- """ +- Applies a force-directed relaxation algorithm to settle circle centers. +- Circles repel each other and are repelled by boundaries. +- """ +- n = centers.shape[0] +- for _ in range(iterations): +- forces = np.zeros_like(centers) +- for i in range(n): +- # Circle-circle repulsion +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist +- force_vec = force_magnitude * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- # Boundary repulsion +- x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) +- centers += step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- return centers ++ ++class CirclePackingOrchestrator: ++ """ ++ Manages a multi-stage circle packing pipeline, structured for clarity and performance. ++ ++ This orchestrator class encapsulates the entire process, from finding a promising ++ initial configuration via a multi-start strategy to refining it with an advanced ++ Simulated Annealing algorithm and final polishing. This structure separates concerns, ++ making the process more modular and maintainable. ++ """ ++ def __init__(self, n=26): ++ self.n = n ++ self.centers = np.zeros((n, 2)) ++ self.best_centers = None ++ self.best_radii = None ++ self.best_sum_radii = -1.0 ++ ++ def _generate_void_config(self, void_center, amplitude, sigma): ++ """Helper to generate initial centers from a grid deformed by a Gaussian push.""" ++ x_coords = np.linspace(0.1, 0.9, 5) ++ y_coords = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords, y_coords) ++ base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T ++ ++ displacements = base_centers_25 - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ mask = distances > 1e-9 ++ ++ push_magnitudes = np.zeros(25) ++ if np.any(mask): ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ displacements[mask] /= distances[mask, np.newaxis] ++ ++ initial_centers = np.zeros((self.n, 2)) ++ initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ initial_centers[25] = void_center ++ return np.clip(initial_centers, 0.0, 1.0) ++ ++ ++ def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): ++ """Performs a vectorized force-directed relaxation phase for speed.""" ++ for _ in range(iters): ++ diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] ++ dists = np.linalg.norm(diff, axis=2) ++ np.fill_diagonal(dists, np.inf) ++ ++ repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) ++ ++ force_magnitudes = np.zeros_like(dists) ++ force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] ++ ++ normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) ++ ++ forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) ++ forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) ++ forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) ++ forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) ++ ++ self.centers += step_size * forces ++ self.centers = np.clip(self.centers, 0.0, 1.0) ++ ++ def _initialize_and_select_best_start(self, num_starts=8): ++ """ ++ Runs a multi-start initialization. Generates several random starting ++ configurations, performs a quick relaxation on each, and selects the ++ best one to seed the main SA optimization. ++ """ ++ best_start_score = -1.0 ++ best_start_centers = None ++ ++ for _ in range(num_starts): ++ void_center = np.random.uniform(0.2, 0.8, 2) ++ amplitude = np.random.uniform(0.05, 0.1) ++ sigma = np.random.uniform(0.1, 0.2) ++ self.centers = self._generate_void_config(void_center, amplitude, sigma) ++ ++ self._force_directed_relaxation_vectorized( ++ iters=300, step_size=0.002, repulsion_strength=0.02, ++ boundary_strength=0.08, repulsion_threshold=0.2, boundary_margin=0.04 ++ ) ++ ++ radii = compute_max_radii(self.centers, max_iterations=100) ++ score = np.sum(radii) ++ ++ if score > best_start_score: ++ best_start_score = score ++ best_start_centers = self.centers.copy() ++ ++ self.centers = best_start_centers ++ self.best_centers = best_start_centers.copy() ++ self.best_radii = compute_max_radii(self.best_centers) ++ self.best_sum_radii = np.sum(self.best_radii) ++ ++ def _select_circle_context_aware(self, current_radii, current_centers): ++ """Intelligently selects a circle to perturb.""" ++ inverse_radii = 1 / (current_radii + 1e-8) ++ dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], ++ current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) ++ boundary_weight = np.exp(-dist_to_boundary / 0.08) ++ combined_weights = inverse_radii * (1 + boundary_weight) ++ selection_probs = combined_weights / np.sum(combined_weights) ++ return np.random.choice(self.n, p=selection_probs) ++ ++ def _simulated_annealing_search(self): ++ """ ++ Performs the main optimization using SA with multi-modal perturbations, ++ adaptive parameters, and a refined stagnation escape mechanism. ++ """ ++ total_iterations = 40000 ++ initial_temp, final_temp = 0.001, 1e-10 ++ initial_perturb_strength, final_perturb_strength = 0.04, 0.0001 ++ ++ current_centers = self.centers.copy() ++ current_radii = self.best_radii.copy() ++ current_sum_radii = self.best_sum_radii ++ ++ swap_prob, cluster_prob = 0.10, 0.15 ++ ++ stagnation_counter, stagnation_threshold = 0, 1500 ++ perturb_boost, boost_factor, boost_decay = 1.0, 4.0, 0.97 ++ temp_reheat_factor = 0.5 ++ ++ min_radii_iters, max_radii_iters = 150, 800 ++ ++ for iteration in range(total_iterations): ++ progress = iteration / total_iterations ++ temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) ++ base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) ++ radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) ++ ++ current_temp = temp_schedule ++ if stagnation_counter >= stagnation_threshold: ++ perturb_boost = boost_factor ++ current_temp += initial_temp * temp_reheat_factor ++ stagnation_counter = 0 ++ ++ candidate_centers = current_centers.copy() ++ rand_val = np.random.rand() ++ ++ if rand_val < swap_prob: ++ if self.n > 1: ++ sorted_indices = np.argsort(current_radii) ++ num_candidates = max(1, self.n // 4) ++ idx_small = np.random.choice(sorted_indices[:num_candidates]) ++ idx_large = np.random.choice(sorted_indices[-num_candidates:]) ++ if idx_small != idx_large: ++ candidate_centers[idx_small], candidate_centers[idx_large] = \ ++ candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() ++ ++ elif rand_val < swap_prob + cluster_prob: ++ primary_idx = self._select_circle_context_aware(current_radii, current_centers) ++ distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) ++ distances[primary_idx] = np.inf ++ neighbor_indices = np.argsort(distances)[:2] ++ indices_to_perturb = np.append(neighbor_indices, primary_idx) ++ ++ eff_strength = base_perturb_strength * perturb_boost * 0.6 ++ displacement = np.random.uniform(-eff_strength, eff_strength, 2) ++ candidate_centers[indices_to_perturb] += displacement ++ ++ else: ++ circle_idx = self._select_circle_context_aware(current_radii, current_centers) ++ max_r = np.max(current_radii) + 1e-8 ++ relative_radius = current_radii[circle_idx] / max_r ++ perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 ++ eff_strength = base_perturb_strength * perturb_factor * perturb_boost ++ displacement = np.random.uniform(-eff_strength, eff_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ ++ candidate_centers = np.clip(candidate_centers, 0.0, 1.0) ++ if perturb_boost > 1.0: ++ perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay ++ ++ candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) ++ candidate_sum_radii = np.sum(candidate_radii) ++ ++ delta_E = candidate_sum_radii - current_sum_radii ++ if delta_E > 0 or (current_temp > 1e-12 and np.random.rand() < math.exp(delta_E / current_temp)): ++ current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii ++ if current_sum_radii > self.best_sum_radii: ++ self.best_sum_radii = current_sum_radii ++ self.best_centers = current_centers.copy() ++ self.best_radii = current_radii.copy() ++ stagnation_counter = 0 ++ else: ++ stagnation_counter += 1 ++ else: ++ stagnation_counter += 1 ++ ++ self.centers = self.best_centers.copy() ++ ++ ++ def pack(self): ++ """Executes the full, orchestrated packing pipeline.""" ++ self._initialize_and_select_best_start(num_starts=8) ++ ++ self._simulated_annealing_search() ++ ++ self.centers = self.best_centers.copy() ++ self._force_directed_relaxation_vectorized( ++ iters=500, step_size=0.0001, repulsion_strength=0.001, ++ boundary_strength=0.01, repulsion_threshold=0.18, boundary_margin=0.02 ++ ) ++ ++ final_radii = compute_max_radii(self.centers, max_iterations=1000) ++ final_sum_radii = np.sum(final_radii) ++ ++ if final_sum_radii > self.best_sum_radii: ++ self.best_radii = final_radii ++ self.best_centers = self.centers ++ ++ return self.best_centers, self.best_radii ++ + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles. This method combines +- a proven asymmetric initialization, a mild force-directed pre-relaxation, +- and a sophisticated Simulated Annealing local search with adaptive heuristics. +- """ +- n = 26 +- +- # 1. Initialization: Asymmetric Gaussian-deformed grid. +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T +- void_center = np.array([0.4, 0.2]) +- amplitude, sigma = 0.06, 0.15 +- +- displacements = base_centers_25 - void_center +- distances = np.linalg.norm(displacements, axis=1) +- mask = distances > 1e-9 +- push_magnitudes = np.zeros(25) +- push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) +- displacements[mask] /= distances[mask, np.newaxis] +- +- centers = np.zeros((n, 2)) +- centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- centers[25] = void_center +- centers = np.clip(centers, 0.0, 1.0) +- +- # 2. Pre-optimization: A mild force-directed relaxation to settle the initial state. +- centers = apply_force_directed_relaxation( +- centers, iterations=500, step_size=0.001, repulsion_strength=0.01, +- repulsion_threshold=0.18, boundary_strength=0.05, boundary_margin=0.03 +- ) +- +- # 3. Main Optimization: Advanced Simulated Annealing with Stagnation Escape. +- radii = compute_max_radii(centers) +- +- best_centers = centers.copy() +- best_radii = radii.copy() +- best_sum_radii = np.sum(radii) +- +- current_centers = centers.copy() +- current_radii = radii.copy() +- current_sum_radii = best_sum_radii +- +- # Tuned SA parameters based on high-performing ancestors for better exploration +- total_iterations = 15000 +- initial_g_perturb_base = 0.04 +- final_g_perturb = 0.0003 +- T_initial, T_final = 0.2, 1e-7 +- +- # Stagnation escape mechanism to kick search out of local optima +- no_improvement_count = 0 +- max_no_improvement_steps = 500 +- current_initial_g_perturb = initial_g_perturb_base +- +- for it in range(total_iterations): +- # Annealing schedules with dynamic perturbation +- g_perturb = current_initial_g_perturb + (final_g_perturb - current_initial_g_perturb) * (it / total_iterations) +- temp = T_initial * (T_final / T_initial)**(it / total_iterations) +- +- candidate_centers = current_centers.copy() +- +- # Adaptive Selection: Prioritize small circles and those near boundaries +- inverse_radii = 1 / (current_radii + 1e-8) +- dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0) +- boundary_weight = np.exp(-dist_to_boundary / 0.1) +- weights = inverse_radii * (1 + boundary_weight) +- probs = weights / np.sum(weights) +- circle_idx = np.random.choice(n, p=probs) +- +- # Adaptive Perturbation: Give larger kicks to smaller circles +- max_r = np.max(current_radii) + 1e-8 +- relative_r = current_radii[circle_idx] / max_r +- # Increased multiplier for more aggressive small circle movement +- perturb_factor = 1.0 + (1.0 - relative_r) * 2.0 +- eff_perturb = g_perturb * perturb_factor +- +- displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) +- +- # Evaluation and Acceptance +- candidate_radii = compute_max_radii(candidate_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- accepted = False +- delta = candidate_sum_radii - current_sum_radii +- if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): +- current_sum_radii = candidate_sum_radii +- current_centers = candidate_centers.copy() +- current_radii = candidate_radii.copy() +- accepted = True +- +- # Update best solution and manage stagnation +- if current_sum_radii > best_sum_radii: +- best_sum_radii = current_sum_radii +- best_centers = current_centers.copy() +- best_radii = current_radii.copy() +- no_improvement_count = 0 # Reset on new best +- elif not accepted: +- no_improvement_count += 1 +- # If stagnated, boost perturbation to escape local optimum +- if no_improvement_count > max_no_improvement_steps: +- current_initial_g_perturb *= 1.2 +- no_improvement_count = 0 +- +- return best_centers, best_radii ++ Constructs a high-density arrangement of 26 circles by instantiating and ++ running the CirclePackingOrchestrator. ++ """ ++ orchestrator = CirclePackingOrchestrator(n=26) ++ centers, radii = orchestrator.pack() ++ return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/main.py new file mode 100644 index 0000000000000000000000000000000000000000..5918ef2671efbcf468839cc285a7495170e0e217 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/main.py @@ -0,0 +1,262 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers, max_iterations=750): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + + +class CirclePackingOrchestrator: + """ + Manages a multi-stage circle packing pipeline, structured for clarity and performance. + + This orchestrator class encapsulates the entire process, from finding a promising + initial configuration via a multi-start strategy to refining it with an advanced + Simulated Annealing algorithm and final polishing. This structure separates concerns, + making the process more modular and maintainable. + """ + def __init__(self, n=26): + self.n = n + self.centers = np.zeros((n, 2)) + self.best_centers = None + self.best_radii = None + self.best_sum_radii = -1.0 + + def _generate_void_config(self, void_center, amplitude, sigma): + """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation phase for speed.""" + for _ in range(iters): + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + np.fill_diagonal(dists, np.inf) + + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _initialize_and_select_best_start(self, num_starts=8): + """ + Runs a multi-start initialization. Generates several random starting + configurations, performs a quick relaxation on each, and selects the + best one to seed the main SA optimization. + """ + best_start_score = -1.0 + best_start_centers = None + + for _ in range(num_starts): + void_center = np.random.uniform(0.2, 0.8, 2) + amplitude = np.random.uniform(0.05, 0.1) + sigma = np.random.uniform(0.1, 0.2) + self.centers = self._generate_void_config(void_center, amplitude, sigma) + + self._force_directed_relaxation_vectorized( + iters=300, step_size=0.002, repulsion_strength=0.02, + boundary_strength=0.08, repulsion_threshold=0.2, boundary_margin=0.04 + ) + + radii = compute_max_radii(self.centers, max_iterations=100) + score = np.sum(radii) + + if score > best_start_score: + best_start_score = score + best_start_centers = self.centers.copy() + + self.centers = best_start_centers + self.best_centers = best_start_centers.copy() + self.best_radii = compute_max_radii(self.best_centers) + self.best_sum_radii = np.sum(self.best_radii) + + def _select_circle_context_aware(self, current_radii, current_centers): + """Intelligently selects a circle to perturb.""" + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + combined_weights = inverse_radii * (1 + boundary_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(self.n, p=selection_probs) + + def _simulated_annealing_search(self): + """ + Performs the main optimization using SA with multi-modal perturbations, + adaptive parameters, and a refined stagnation escape mechanism. + """ + total_iterations = 40000 + initial_temp, final_temp = 0.001, 1e-10 + initial_perturb_strength, final_perturb_strength = 0.04, 0.0001 + + current_centers = self.centers.copy() + current_radii = self.best_radii.copy() + current_sum_radii = self.best_sum_radii + + swap_prob, cluster_prob = 0.10, 0.15 + + stagnation_counter, stagnation_threshold = 0, 1500 + perturb_boost, boost_factor, boost_decay = 1.0, 4.0, 0.97 + temp_reheat_factor = 0.5 + + min_radii_iters, max_radii_iters = 150, 800 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) + + current_temp = temp_schedule + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp += initial_temp * temp_reheat_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_prob: + if self.n > 1: + sorted_indices = np.argsort(current_radii) + num_candidates = max(1, self.n // 4) + idx_small = np.random.choice(sorted_indices[:num_candidates]) + idx_large = np.random.choice(sorted_indices[-num_candidates:]) + if idx_small != idx_large: + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() + + elif rand_val < swap_prob + cluster_prob: + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + + eff_strength = base_perturb_strength * perturb_boost * 0.6 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement + + else: + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + eff_strength = base_perturb_strength * perturb_factor * perturb_boost + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[circle_idx] += displacement + + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (current_temp > 1e-12 and np.random.rand() < math.exp(delta_E / current_temp)): + current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii + if current_sum_radii > self.best_sum_radii: + self.best_sum_radii = current_sum_radii + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + self.centers = self.best_centers.copy() + + + def pack(self): + """Executes the full, orchestrated packing pipeline.""" + self._initialize_and_select_best_start(num_starts=8) + + self._simulated_annealing_search() + + self.centers = self.best_centers.copy() + self._force_directed_relaxation_vectorized( + iters=500, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.01, repulsion_threshold=0.18, boundary_margin=0.02 + ) + + final_radii = compute_max_radii(self.centers, max_iterations=1000) + final_sum_radii = np.sum(final_radii) + + if final_sum_radii > self.best_sum_radii: + self.best_radii = final_radii + self.best_centers = self.centers + + return self.best_centers, self.best_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the CirclePackingOrchestrator. + """ + orchestrator = CirclePackingOrchestrator(n=26) + centers, radii = orchestrator.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/original.py new file mode 100644 index 0000000000000000000000000000000000000000..f1c7e54d0435ebc31fdc5394d04006f30db3885a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/original.py @@ -0,0 +1,184 @@ +# EVOLVE-BLOCK-START +""" +Constructor-based circle packing for n=26 circles using a hybrid approach: +a force-directed pre-relaxation followed by an advanced Simulated Annealing search. +""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + """ + n = centers.shape[0] + # Initialize radii based on distance to boundaries (vectorized) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps until convergence + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles. This method combines + a proven asymmetric initialization, a mild force-directed pre-relaxation, + and a sophisticated Simulated Annealing local search with adaptive heuristics. + """ + n = 26 + + # 1. Initialization: Asymmetric Gaussian-deformed grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + void_center = np.array([0.4, 0.2]) + amplitude, sigma = 0.06, 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 2. Pre-optimization: A mild force-directed relaxation to settle the initial state. + centers = apply_force_directed_relaxation( + centers, iterations=500, step_size=0.001, repulsion_strength=0.01, + repulsion_threshold=0.18, boundary_strength=0.05, boundary_margin=0.03 + ) + + # 3. Main Optimization: Advanced Simulated Annealing with Stagnation Escape. + radii = compute_max_radii(centers) + + best_centers = centers.copy() + best_radii = radii.copy() + best_sum_radii = np.sum(radii) + + current_centers = centers.copy() + current_radii = radii.copy() + current_sum_radii = best_sum_radii + + # Tuned SA parameters based on high-performing ancestors for better exploration + total_iterations = 15000 + initial_g_perturb_base = 0.04 + final_g_perturb = 0.0003 + T_initial, T_final = 0.2, 1e-7 + + # Stagnation escape mechanism to kick search out of local optima + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_g_perturb = initial_g_perturb_base + + for it in range(total_iterations): + # Annealing schedules with dynamic perturbation + g_perturb = current_initial_g_perturb + (final_g_perturb - current_initial_g_perturb) * (it / total_iterations) + temp = T_initial * (T_final / T_initial)**(it / total_iterations) + + candidate_centers = current_centers.copy() + + # Adaptive Selection: Prioritize small circles and those near boundaries + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.1) + weights = inverse_radii * (1 + boundary_weight) + probs = weights / np.sum(weights) + circle_idx = np.random.choice(n, p=probs) + + # Adaptive Perturbation: Give larger kicks to smaller circles + max_r = np.max(current_radii) + 1e-8 + relative_r = current_radii[circle_idx] / max_r + # Increased multiplier for more aggressive small circle movement + perturb_factor = 1.0 + (1.0 - relative_r) * 2.0 + eff_perturb = g_perturb * perturb_factor + + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluation and Acceptance + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + accepted = False + delta = candidate_sum_radii - current_sum_radii + if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best + elif not accepted: + no_improvement_count += 1 + # If stagnated, boost perturbation to escape local optimum + if no_improvement_count > max_no_improvement_steps: + current_initial_g_perturb *= 1.2 + no_improvement_count = 0 + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..5c3cd689df1b93bd2093f5eb83c9b44efb7d9d35 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/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. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..75173dcec895504402c1067969a6df17d7b443cc --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/results +Run 1/1 completed in 87.47 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.454803266030448 + 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} + private: {'reported_sum_of_radii': 2.454803266030448} + visualization_path: + execution_time_mean: 87.47112137591466 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..dcfd27586e95bfcc58e81378dff9419f8ad98438 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.454803266030448, + "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 + }, + "private": { + "reported_sum_of_radii": 2.454803266030448 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_187/results/packing_viz.png", + "execution_time_mean": 87.47112137591466, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..37ca5c4b0c4d4e550e188087b84f21a217fd8d13 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/best/rewrite.txt @@ -0,0 +1,253 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers, max_iterations=750): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + + +class CirclePackingOrchestrator: + """ + Manages a multi-stage circle packing pipeline, structured for clarity and performance. + + This orchestrator class encapsulates the entire process, from finding a promising + initial configuration via a multi-start strategy to refining it with an advanced + Simulated Annealing algorithm and final polishing. This structure separates concerns, + making the process more modular and maintainable. + """ + def __init__(self, n=26): + self.n = n + self.centers = np.zeros((n, 2)) + self.best_centers = None + self.best_radii = None + self.best_sum_radii = -1.0 + + def _generate_void_config(self, void_center, amplitude, sigma): + """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation phase for speed.""" + for _ in range(iters): + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + np.fill_diagonal(dists, np.inf) + + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _initialize_and_select_best_start(self, num_starts=8): + """ + Runs a multi-start initialization. Generates several random starting + configurations, performs a quick relaxation on each, and selects the + best one to seed the main SA optimization. + """ + best_start_score = -1.0 + best_start_centers = None + + for _ in range(num_starts): + void_center = np.random.uniform(0.2, 0.8, 2) + amplitude = np.random.uniform(0.05, 0.1) + sigma = np.random.uniform(0.1, 0.2) + self.centers = self._generate_void_config(void_center, amplitude, sigma) + + self._force_directed_relaxation_vectorized( + iters=300, step_size=0.002, repulsion_strength=0.02, + boundary_strength=0.08, repulsion_threshold=0.2, boundary_margin=0.04 + ) + + radii = compute_max_radii(self.centers, max_iterations=100) + score = np.sum(radii) + + if score > best_start_score: + best_start_score = score + best_start_centers = self.centers.copy() + + self.centers = best_start_centers + self.best_centers = best_start_centers.copy() + self.best_radii = compute_max_radii(self.best_centers) + self.best_sum_radii = np.sum(self.best_radii) + + def _select_circle_context_aware(self, current_radii, current_centers): + """Intelligently selects a circle to perturb.""" + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + combined_weights = inverse_radii * (1 + boundary_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(self.n, p=selection_probs) + + def _simulated_annealing_search(self): + """ + Performs the main optimization using SA with multi-modal perturbations, + adaptive parameters, and a refined stagnation escape mechanism. + """ + total_iterations = 40000 + initial_temp, final_temp = 0.001, 1e-10 + initial_perturb_strength, final_perturb_strength = 0.04, 0.0001 + + current_centers = self.centers.copy() + current_radii = self.best_radii.copy() + current_sum_radii = self.best_sum_radii + + swap_prob, cluster_prob = 0.10, 0.15 + + stagnation_counter, stagnation_threshold = 0, 1500 + perturb_boost, boost_factor, boost_decay = 1.0, 4.0, 0.97 + temp_reheat_factor = 0.5 + + min_radii_iters, max_radii_iters = 150, 800 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) + + current_temp = temp_schedule + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp += initial_temp * temp_reheat_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_prob: + if self.n > 1: + sorted_indices = np.argsort(current_radii) + num_candidates = max(1, self.n // 4) + idx_small = np.random.choice(sorted_indices[:num_candidates]) + idx_large = np.random.choice(sorted_indices[-num_candidates:]) + if idx_small != idx_large: + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() + + elif rand_val < swap_prob + cluster_prob: + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + + eff_strength = base_perturb_strength * perturb_boost * 0.6 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement + + else: + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + eff_strength = base_perturb_strength * perturb_factor * perturb_boost + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[circle_idx] += displacement + + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (current_temp > 1e-12 and np.random.rand() < math.exp(delta_E / current_temp)): + current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii + if current_sum_radii > self.best_sum_radii: + self.best_sum_radii = current_sum_radii + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + self.centers = self.best_centers.copy() + + + def pack(self): + """Executes the full, orchestrated packing pipeline.""" + self._initialize_and_select_best_start(num_starts=8) + + self._simulated_annealing_search() + + self.centers = self.best_centers.copy() + self._force_directed_relaxation_vectorized( + iters=500, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.01, repulsion_threshold=0.18, boundary_margin=0.02 + ) + + final_radii = compute_max_radii(self.centers, max_iterations=1000) + final_sum_radii = np.sum(final_radii) + + if final_sum_radii > self.best_sum_radii: + self.best_radii = final_radii + self.best_centers = self.centers + + return self.best_centers, self.best_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the CirclePackingOrchestrator. + """ + orchestrator = CirclePackingOrchestrator(n=26) + centers, radii = orchestrator.pack() + return centers, radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..78b368a6915d6dda31f773e8fe8101f2f535ed11 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..29fc1ca66470a2e57e3228b5c013fde5d6aa3ffe --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 0.9597642169962064 + 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} + private: {'reported_sum_of_radii': 0.9597642169962064} + visualization_path: + execution_time_mean: 0.002032745163887739 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..eca416bdd21a48c7388da05968472a1ba1523aa7 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 0.9597642169962064, + "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 + }, + "private": { + "reported_sum_of_radii": 0.9597642169962064 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_0/results/packing_viz.png", + "execution_time_mean": 0.002032745163887739, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2bb539c859f7e42015a13ee2f51ee0d9d87dbd20 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..e358c6d2e63e8f7a5e276f16e96aec780460b8d5 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.7873680766471653 + 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} + private: {'reported_sum_of_radii': 1.7873680766471653} + visualization_path: + execution_time_mean: 0.002029381226748228 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..cf5ce98d6b82fcaaca4467dcac9f791460eb0e69 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.7873680766471653, + "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 + }, + "private": { + "reported_sum_of_radii": 1.7873680766471653 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_1/results/packing_viz.png", + "execution_time_mean": 0.002029381226748228, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..79f356367ea791af92a8eab34d674ce27dab3551 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..02c88e930491c5a24e4eef5af61c8a7aa865fae4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/edit.diff @@ -0,0 +1,125 @@ +--- a/original.py ++++ b/original.py +@@ -1,94 +1,106 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + +- # Place circles in a structured pattern +- # This is a simple pattern - evolution will improve this ++ # Using a 5-5-6-5-5 column-like structure. ++ # This structure is inspired by known good packings for N=26 and provides ++ # much better space utilization than the previous concentric ring model. ++ # It avoids the need for clipping, which created tiny, inefficient circles. + +- # First, place a large circle in the center +- centers[0] = [0.5, 0.5] ++ # x-coordinates for the 5 columns ++ x_cols = np.linspace(0.1, 0.9, 5) + +- # Place 8 circles around it in a ring +- for i in range(8): +- angle = 2 * np.pi * i / 8 +- centers[i + 1] = [0.5 + 0.22 * np.cos(angle), 0.5 + 0.22 * np.sin(angle)] ++ # y-coordinates for columns with 5 circles ++ y_5 = np.linspace(0.1, 0.9, 5) + +- # Place 16 more circles in an outer ring +- for i in range(16): +- angle = 2 * np.pi * i / 16 +- centers[i + 9] = [0.5 + 0.41 * np.cos(angle), 0.5 + 0.41 * np.sin(angle)] ++ # y-coordinates for the central column with 6 circles ++ y_6 = np.linspace(1/12, 11/12, 6) + +- # Additional positioning adjustment to make sure all circles +- # are inside the square and don't overlap +- # Clip to ensure everything is inside the unit square +- centers = np.clip(centers, 0.01, 0.99) ++ count = 0 ++ # Arrange circles column by column ++ for i in range(5): ++ x = x_cols[i] ++ ++ # The central column (i=2) has 6 circles ++ if i == 2: ++ for y in y_6: ++ centers[count] = [x, y] ++ count += 1 ++ # The other four columns have 5 circles each ++ else: ++ for y in y_5: ++ centers[count] = [x, y] ++ count += 1 ++ ++ # This construction places all centers within the (0,1) square, ++ # so no clipping is necessary. + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/main.py new file mode 100644 index 0000000000000000000000000000000000000000..e377c515cfd882e949dd853539d5a7fe0af3f981 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/main.py @@ -0,0 +1,106 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Using a 5-5-6-5-5 column-like structure. + # This structure is inspired by known good packings for N=26 and provides + # much better space utilization than the previous concentric ring model. + # It avoids the need for clipping, which created tiny, inefficient circles. + + # x-coordinates for the 5 columns + x_cols = np.linspace(0.1, 0.9, 5) + + # y-coordinates for columns with 5 circles + y_5 = np.linspace(0.1, 0.9, 5) + + # y-coordinates for the central column with 6 circles + y_6 = np.linspace(1/12, 11/12, 6) + + count = 0 + # Arrange circles column by column + for i in range(5): + x = x_cols[i] + + # The central column (i=2) has 6 circles + if i == 2: + for y in y_6: + centers[count] = [x, y] + count += 1 + # The other four columns have 5 circles each + else: + for y in y_5: + centers[count] = [x, y] + count += 1 + + # This construction places all centers within the (0,1) square, + # so no clipping is necessary. + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/original.py new file mode 100644 index 0000000000000000000000000000000000000000..b51170bfb8b3df3b29922351f29bcf11f69e7443 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/original.py @@ -0,0 +1,94 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Place circles in a structured pattern + # This is a simple pattern - evolution will improve this + + # First, place a large circle in the center + centers[0] = [0.5, 0.5] + + # Place 8 circles around it in a ring + for i in range(8): + angle = 2 * np.pi * i / 8 + centers[i + 1] = [0.5 + 0.22 * np.cos(angle), 0.5 + 0.22 * np.sin(angle)] + + # Place 16 more circles in an outer ring + for i in range(16): + angle = 2 * np.pi * i / 16 + centers[i + 9] = [0.5 + 0.41 * np.cos(angle), 0.5 + 0.41 * np.sin(angle)] + + # Additional positioning adjustment to make sure all circles + # are inside the square and don't overlap + # Clip to ensure everything is inside the unit square + centers = np.clip(centers, 0.01, 0.99) + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..07946c828892a8db52816ab701a48606aa2e786c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.853356327835797 + 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} + private: {'reported_sum_of_radii': 1.853356327835797} + visualization_path: + execution_time_mean: 0.0020518279634416103 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..78a75ae2964f70b07164affbe0f1279ac38d9304 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.853356327835797, + "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 + }, + "private": { + "reported_sum_of_radii": 1.853356327835797 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_10/results/packing_viz.png", + "execution_time_mean": 0.0020518279634416103, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..a3bb592dde36c1fbec7f219d8deeb1dc49d6c6c2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_10/search_replace.txt @@ -0,0 +1,122 @@ + +columnar_packing_55655 + + + +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. + +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. + +This change addresses the observed issues: +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. +2. **Improves Space Utilization:** A grid-like structure fills the square more evenly and densely than concentric rings. +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. + +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. + + + +<<<<<<< SEARCH +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Place circles in a structured pattern + # This is a simple pattern - evolution will improve this + + # First, place a large circle in the center + centers[0] = [0.5, 0.5] + + # Place 8 circles around it in a ring + for i in range(8): + angle = 2 * np.pi * i / 8 + centers[i + 1] = [0.5 + 0.22 * np.cos(angle), 0.5 + 0.22 * np.sin(angle)] + + # Place 16 more circles in an outer ring + for i in range(16): + angle = 2 * np.pi * i / 16 + centers[i + 9] = [0.5 + 0.41 * np.cos(angle), 0.5 + 0.41 * np.sin(angle)] + + # Additional positioning adjustment to make sure all circles + # are inside the square and don't overlap + # Clip to ensure everything is inside the unit square + centers = np.clip(centers, 0.01, 0.99) + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii +======= +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Using a 5-5-6-5-5 column-like structure. + # This structure is inspired by known good packings for N=26 and provides + # much better space utilization than the previous concentric ring model. + # It avoids the need for clipping, which created tiny, inefficient circles. + + # x-coordinates for the 5 columns + x_cols = np.linspace(0.1, 0.9, 5) + + # y-coordinates for columns with 5 circles + y_5 = np.linspace(0.1, 0.9, 5) + + # y-coordinates for the central column with 6 circles + y_6 = np.linspace(1/12, 11/12, 6) + + count = 0 + # Arrange circles column by column + for i in range(5): + x = x_cols[i] + + # The central column (i=2) has 6 circles + if i == 2: + for y in y_6: + centers[count] = [x, y] + count += 1 + # The other four columns have 5 circles each + else: + for y in y_5: + centers[count] = [x, y] + count += 1 + + # This construction places all centers within the (0,1) square, + # so no clipping is necessary. + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76ee5a48e1c26850720db90bc1591bf4974e660f Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..dc753ce4fc4de1c578ae353d34b8aaee5b693d6c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/edit.diff @@ -0,0 +1,220 @@ +--- a/original.py ++++ b/original.py +@@ -1,186 +1,214 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Breaking the initial symmetry by using an off-center void at (0.4, 0.2) + # prevents the relaxation from getting stuck in an overly-ordered local optimum. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.06 # The maximum distance to push a circle. Increased to create a larger void. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This approach uses a high-energy "exploration" phase to break symmetry + # and find a good general configuration, followed by a low-energy + # "refinement" phase to fine-tune the positions. + + # Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to quickly move circles + # out of the initial grid structure and explore new arrangements. +- exploration_iters = 250 ++ exploration_iters = 300 + exploration_step_size = 0.003 +- exploration_repulsion_strength = 0.02 ++ exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement + boundary_margin = 0.04 # Use a smaller margin to utilize edge space better + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 +- refinement_repulsion_strength = 0.008 ++ refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 # Tighter threshold for settling + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ # Stage 3: Ultra-Low-Energy Annealing ("Polishing") ++ # This stage uses very weak forces and many iterations for final micro-adjustments. ++ annealing_iters = 800 ++ annealing_step_size = 0.0001 ++ annealing_repulsion_strength = 0.004 ++ annealing_boundary_strength = 0.02 ++ annealing_repulsion_threshold = 0.18 # Tighter threshold for final packing ++ ++ for _ in range(annealing_iters): ++ forces = np.zeros_like(centers) ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < annealing_repulsion_threshold: ++ force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist ++ force_vec = force_mag * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) ++ centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.zeros(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/main.py new file mode 100644 index 0000000000000000000000000000000000000000..ba8a81be8edd2ac2c5ca7ec1d92c9446acbffc7c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/main.py @@ -0,0 +1,214 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Breaking the initial symmetry by using an off-center void at (0.4, 0.2) + # prevents the relaxation from getting stuck in an overly-ordered local optimum. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.06 # The maximum distance to push a circle. Increased to create a larger void. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This approach uses a high-energy "exploration" phase to break symmetry + # and find a good general configuration, followed by a low-energy + # "refinement" phase to fine-tune the positions. + + # Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to quickly move circles + # out of the initial grid structure and explore new arrangements. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement + boundary_margin = 0.04 # Use a smaller margin to utilize edge space better + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 # Tighter threshold for settling + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # This stage uses very weak forces and many iterations for final micro-adjustments. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 # Tighter threshold for final packing + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.zeros(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/original.py new file mode 100644 index 0000000000000000000000000000000000000000..529dc0511969931cf633b8a70305b19b2f66747f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/original.py @@ -0,0 +1,186 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Breaking the initial symmetry by using an off-center void at (0.4, 0.2) + # prevents the relaxation from getting stuck in an overly-ordered local optimum. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.06 # The maximum distance to push a circle. Increased to create a larger void. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This approach uses a high-energy "exploration" phase to break symmetry + # and find a good general configuration, followed by a low-energy + # "refinement" phase to fine-tune the positions. + + # Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to quickly move circles + # out of the initial grid structure and explore new arrangements. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement + boundary_margin = 0.04 # Use a smaller margin to utilize edge space better + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 # Tighter threshold for settling + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.zeros(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..f1d5316b71afece767b8ed51eeaed43834fe281d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/results +Run 1/1 completed in 1.75 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9808569554223658 + 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} + private: {'reported_sum_of_radii': 1.9808569554223658} + visualization_path: + execution_time_mean: 1.751810641027987 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..d1e33c51666bcd5348ab4314137f0cbc4368ca06 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9808569554223658, + "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 + }, + "private": { + "reported_sum_of_radii": 1.9808569554223658 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_102/results/packing_viz.png", + "execution_time_mean": 1.751810641027987, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..17b194fd9e20d4a1a0080e618af631c42aa45d27 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_102/search_replace.txt @@ -0,0 +1,100 @@ +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. + +### Change 1: Strengthen Relaxation Stages + + +strengthen_relaxation_stages + + + +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. + + + +<<<<<<< SEARCH + # Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to quickly move circles + # out of the initial grid structure and explore new arrangements. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 +======= + # Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to quickly move circles + # out of the initial grid structure and explore new arrangements. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 +>>>>>>> REPLACE + + +<<<<<<< SEARCH + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 +======= + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 +>>>>>>> REPLACE + + +### Change 2: Add Annealing Stage + + +add_annealing_stage + + + +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. + + + +<<<<<<< SEARCH + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) +======= + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # This stage uses very weak forces and many iterations for final micro-adjustments. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 # Tighter threshold for final packing + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f06d8804cad4cdaec15f7d793b06c7e78fc2156d Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..a172a3294407451995750fef286c71a423bba6cc --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/results +Run 1/1 completed in 2.19 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9605693402727424 + 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} + private: {'reported_sum_of_radii': 1.9605693402727424} + visualization_path: + execution_time_mean: 2.1865705880336463 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..cc87e4cb8540ff8183d9bff0fa371efd1fd275d6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9605693402727424, + "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 + }, + "private": { + "reported_sum_of_radii": 1.9605693402727424 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_103/results/packing_viz.png", + "execution_time_mean": 2.1865705880336463, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38e2391590b2670c8150a29ecbf4579918756047 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..1164550e10dd3bbd29603252bf4e9cc32802666f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/edit.diff @@ -0,0 +1,239 @@ +--- a/original.py ++++ b/original.py +@@ -1,191 +1,229 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def _relax_stage(centers, n, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """ + Helper function to run a single stage of force-directed relaxation. + """ + for _ in range(iters): + forces = np.zeros_like(centers) + + # Calculate pairwise forces + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + # Repulsion force magnitude decreases linearly with distance, up to a threshold + force_mag = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Calculate boundary forces + for i in range(n): + x, y = centers[i] + # Force pushing away from boundaries if too close + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + # Update centers and clip to stay within the unit square + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Changed from (0.4, 0.4) to (0.4, 0.2) to break symmetry and achieve better packing. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + +- # Increased amplitude to create a larger initial void, allowing more room for exploration. +- amplitude = 0.06 # Increased from 0.05 ++ # Increased amplitude to create a larger, more chaotic initial state. ++ amplitude = 0.10 # Increased from 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + +- # 4. Stage 1: High-Energy Exploration ("Shaking") +- # Increased iterations and strength to break the grid structure more effectively. ++ # 4. Stage 1: Vortex Disruption (NEW) ++ # This new stage applies a rotational force to violently break the grid symmetry, ++ # helping the system escape the initial ordered local minimum. ++ vortex_iters = 75 ++ vortex_step_size = 0.002 ++ vortex_center = np.array([0.5, 0.5]) ++ vortex_strength = 0.008 ++ vortex_repulsion_strength = 0.015 # Add repulsion to prevent collapse ++ vortex_boundary_strength = 0.1 ++ vortex_repulsion_threshold = 0.20 ++ vortex_boundary_margin = 0.04 ++ ++ for _ in range(vortex_iters): ++ forces = np.zeros_like(centers) ++ for i in range(n): ++ # Rotational force ++ vec_from_center = centers[i] - vortex_center ++ forces[i] += vortex_strength * np.array([-vec_from_center[1], vec_from_center[0]]) ++ # Repulsion force ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < vortex_repulsion_threshold: ++ force_mag = vortex_repulsion_strength * (vortex_repulsion_threshold - dist) / dist ++ force_vec = force_mag * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ # Boundary forces ++ for i in range(n): ++ x, y = centers[i] ++ if x < vortex_boundary_margin: forces[i, 0] += vortex_boundary_strength * (vortex_boundary_margin - x) ++ if x > 1 - vortex_boundary_margin: forces[i, 0] -= vortex_boundary_strength * (x - (1 - vortex_boundary_margin)) ++ if y < vortex_boundary_margin: forces[i, 1] += vortex_boundary_strength * (y - (1 - vortex_boundary_margin)) ++ if y > 1 - vortex_boundary_margin: forces[i, 1] -= vortex_boundary_strength * (y - (1 - vortex_boundary_margin)) ++ centers += vortex_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ ++ # 5. Stage 2: High-Energy Exploration ("Shaking") ++ # This stage now operates on a more chaotic configuration from the vortex. + exploration_iters = 350 # Increased from 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 # Increased from 0.02 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + exploration_boundary_margin = 0.04 # Initial broader margin + + centers = _relax_stage(centers, n, exploration_iters, exploration_step_size, + exploration_repulsion_strength, exploration_boundary_strength, + exploration_repulsion_threshold, exploration_boundary_margin) + +- # 5. Stage 2: Low-Energy Refinement ("Settling") ++ # 6. Stage 3: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 600 # Increased from 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 # Increased from 0.008 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + refinement_boundary_margin = 0.02 # Tighter margin for finer packing against boundaries + + centers = _relax_stage(centers, n, refinement_iters, refinement_step_size, + refinement_repulsion_strength, refinement_boundary_strength, + refinement_repulsion_threshold, refinement_boundary_margin) + +- # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") - NEW STAGE ++ # 7. Stage 4: Ultra-Low-Energy Annealing ("Polishing") + # Final micro-adjustments with very weak forces and many iterations for precise packing. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + annealing_boundary_margin = 0.01 # Even tighter margin for final precision + + centers = _relax_stage(centers, n, annealing_iters, annealing_step_size, + annealing_repulsion_strength, annealing_boundary_strength, + annealing_repulsion_threshold, annealing_boundary_margin) + +- # 7. Compute maximum valid radii for the final configuration. ++ # 8. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized for efficiency). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero if sum_r is effectively zero + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change before updating to avoid unnecessary iterations + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changed_in_pass = True + else: # If both radii are already ~0, ensure they are exactly 0 + if radii[i] > 1e-12 or radii[j] > 1e-12: # Only change if not already near zero + radii[i] = 0 + radii[j] = 0 + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/main.py new file mode 100644 index 0000000000000000000000000000000000000000..dad4034e1a764ce5f7d98dbf6e6aac967c29a761 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/main.py @@ -0,0 +1,229 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def _relax_stage(centers, n, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """ + Helper function to run a single stage of force-directed relaxation. + """ + for _ in range(iters): + forces = np.zeros_like(centers) + + # Calculate pairwise forces + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + # Repulsion force magnitude decreases linearly with distance, up to a threshold + force_mag = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Calculate boundary forces + for i in range(n): + x, y = centers[i] + # Force pushing away from boundaries if too close + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + # Update centers and clip to stay within the unit square + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Changed from (0.4, 0.4) to (0.4, 0.2) to break symmetry and achieve better packing. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger, more chaotic initial state. + amplitude = 0.10 # Increased from 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Stage 1: Vortex Disruption (NEW) + # This new stage applies a rotational force to violently break the grid symmetry, + # helping the system escape the initial ordered local minimum. + vortex_iters = 75 + vortex_step_size = 0.002 + vortex_center = np.array([0.5, 0.5]) + vortex_strength = 0.008 + vortex_repulsion_strength = 0.015 # Add repulsion to prevent collapse + vortex_boundary_strength = 0.1 + vortex_repulsion_threshold = 0.20 + vortex_boundary_margin = 0.04 + + for _ in range(vortex_iters): + forces = np.zeros_like(centers) + for i in range(n): + # Rotational force + vec_from_center = centers[i] - vortex_center + forces[i] += vortex_strength * np.array([-vec_from_center[1], vec_from_center[0]]) + # Repulsion force + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < vortex_repulsion_threshold: + force_mag = vortex_repulsion_strength * (vortex_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary forces + for i in range(n): + x, y = centers[i] + if x < vortex_boundary_margin: forces[i, 0] += vortex_boundary_strength * (vortex_boundary_margin - x) + if x > 1 - vortex_boundary_margin: forces[i, 0] -= vortex_boundary_strength * (x - (1 - vortex_boundary_margin)) + if y < vortex_boundary_margin: forces[i, 1] += vortex_boundary_strength * (y - (1 - vortex_boundary_margin)) + if y > 1 - vortex_boundary_margin: forces[i, 1] -= vortex_boundary_strength * (y - (1 - vortex_boundary_margin)) + centers += vortex_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + + # 5. Stage 2: High-Energy Exploration ("Shaking") + # This stage now operates on a more chaotic configuration from the vortex. + exploration_iters = 350 # Increased from 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 # Increased from 0.02 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + exploration_boundary_margin = 0.04 # Initial broader margin + + centers = _relax_stage(centers, n, exploration_iters, exploration_step_size, + exploration_repulsion_strength, exploration_boundary_strength, + exploration_repulsion_threshold, exploration_boundary_margin) + + # 6. Stage 3: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 600 # Increased from 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 # Increased from 0.008 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + refinement_boundary_margin = 0.02 # Tighter margin for finer packing against boundaries + + centers = _relax_stage(centers, n, refinement_iters, refinement_step_size, + refinement_repulsion_strength, refinement_boundary_strength, + refinement_repulsion_threshold, refinement_boundary_margin) + + # 7. Stage 4: Ultra-Low-Energy Annealing ("Polishing") + # Final micro-adjustments with very weak forces and many iterations for precise packing. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + annealing_boundary_margin = 0.01 # Even tighter margin for final precision + + centers = _relax_stage(centers, n, annealing_iters, annealing_step_size, + annealing_repulsion_strength, annealing_boundary_strength, + annealing_repulsion_threshold, annealing_boundary_margin) + + # 8. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized for efficiency). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero if sum_r is effectively zero + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change before updating to avoid unnecessary iterations + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changed_in_pass = True + else: # If both radii are already ~0, ensure they are exactly 0 + if radii[i] > 1e-12 or radii[j] > 1e-12: # Only change if not already near zero + radii[i] = 0 + radii[j] = 0 + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/original.py new file mode 100644 index 0000000000000000000000000000000000000000..91887f33f679655ddbd7522068a88ddc46b4cb67 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/original.py @@ -0,0 +1,191 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def _relax_stage(centers, n, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """ + Helper function to run a single stage of force-directed relaxation. + """ + for _ in range(iters): + forces = np.zeros_like(centers) + + # Calculate pairwise forces + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + # Repulsion force magnitude decreases linearly with distance, up to a threshold + force_mag = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Calculate boundary forces + for i in range(n): + x, y = centers[i] + # Force pushing away from boundaries if too close + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + # Update centers and clip to stay within the unit square + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Changed from (0.4, 0.4) to (0.4, 0.2) to break symmetry and achieve better packing. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void, allowing more room for exploration. + amplitude = 0.06 # Increased from 0.05 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 350 # Increased from 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 # Increased from 0.02 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + exploration_boundary_margin = 0.04 # Initial broader margin + + centers = _relax_stage(centers, n, exploration_iters, exploration_step_size, + exploration_repulsion_strength, exploration_boundary_strength, + exploration_repulsion_threshold, exploration_boundary_margin) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 600 # Increased from 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 # Increased from 0.008 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + refinement_boundary_margin = 0.02 # Tighter margin for finer packing against boundaries + + centers = _relax_stage(centers, n, refinement_iters, refinement_step_size, + refinement_repulsion_strength, refinement_boundary_strength, + refinement_repulsion_threshold, refinement_boundary_margin) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") - NEW STAGE + # Final micro-adjustments with very weak forces and many iterations for precise packing. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + annealing_boundary_margin = 0.01 # Even tighter margin for final precision + + centers = _relax_stage(centers, n, annealing_iters, annealing_step_size, + annealing_repulsion_strength, annealing_boundary_strength, + annealing_repulsion_threshold, annealing_boundary_margin) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized for efficiency). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero if sum_r is effectively zero + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change before updating to avoid unnecessary iterations + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changed_in_pass = True + else: # If both radii are already ~0, ensure they are exactly 0 + if radii[i] > 1e-12 or radii[j] > 1e-12: # Only change if not already near zero + radii[i] = 0 + radii[j] = 0 + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..a8d35523aea9ca13e433c550a7c9654bcaa62121 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/results +Run 1/1 completed in 2.24 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9785014833887988 + 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} + private: {'reported_sum_of_radii': 1.9785014833887988} + visualization_path: + execution_time_mean: 2.236732121091336 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..6c0fdbd41c6524c60678402e8c5ad92f18a61b14 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9785014833887988, + "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 + }, + "private": { + "reported_sum_of_radii": 1.9785014833887988 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_104/results/packing_viz.png", + "execution_time_mean": 2.236732121091336, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..1abe58c7c9184f557930a94f436c1f46df5945e4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_104/search_replace.txt @@ -0,0 +1,175 @@ +Based on my analysis of the visualization, the current circle packing is trapped in a highly symmetric, grid-like local minimum. This is evident from the straight rows of circles in the upper half and the inefficient arrangement of four small circles pinning the large central one created by the void. Such ordered structures prevent the circles from rearranging into a denser, more amorphous state that would yield a higher sum of radii. + +To break out of this unproductive local minimum, I propose a two-part strategy to introduce more chaos early in the process: +1. **Increase Initial Deformation**: I will significantly increase the amplitude of the initial Gaussian push. This will displace the circles more forcefully from their grid positions, creating a more disordered starting configuration. +2. **Introduce a Vortex Stage**: I will add a new, short "Vortex Disruption" stage immediately after the initial push. This stage applies a rotational force to all circles around the center of the square, effectively shearing the grid structure apart. This is a powerful technique to break symmetries and linear alignments. + +Together, these changes will ensure the subsequent relaxation stages begin with a much more chaotic and promising arrangement, greatly increasing the chances of settling into a superior, denser packing. I will implement this as a single, cohesive change that includes the new stage and renumbers the existing stages for clarity. + + +add_vortex_stage_and_increase_chaos + + +The visualization shows a packing stuck in an inefficient, grid-like local minimum. To solve this, I'm making the initial process more chaotic. I've increased the `amplitude` of the Gaussian push for a stronger initial deformation. More importantly, I've inserted a new "Vortex Disruption" stage after initialization. This stage applies a rotational force, shearing the grid structure to break the linear alignments trapping the circles. This creates a disordered state, allowing the subsequent relaxation stages to find a denser configuration. I have also renumbered the comments for the following stages to maintain clarity. + + +<<<<<<< SEARCH + # Increased amplitude to create a larger initial void, allowing more room for exploration. + amplitude = 0.06 # Increased from 0.05 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 350 # Increased from 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 # Increased from 0.02 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + exploration_boundary_margin = 0.04 # Initial broader margin + + centers = _relax_stage(centers, n, exploration_iters, exploration_step_size, + exploration_repulsion_strength, exploration_boundary_strength, + exploration_repulsion_threshold, exploration_boundary_margin) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 600 # Increased from 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 # Increased from 0.008 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + refinement_boundary_margin = 0.02 # Tighter margin for finer packing against boundaries + + centers = _relax_stage(centers, n, refinement_iters, refinement_step_size, + refinement_repulsion_strength, refinement_boundary_strength, + refinement_repulsion_threshold, refinement_boundary_margin) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") - NEW STAGE + # Final micro-adjustments with very weak forces and many iterations for precise packing. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + annealing_boundary_margin = 0.01 # Even tighter margin for final precision + + centers = _relax_stage(centers, n, annealing_iters, annealing_step_size, + annealing_repulsion_strength, annealing_boundary_strength, + annealing_repulsion_threshold, annealing_boundary_margin) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii +======= + # Increased amplitude to create a larger, more chaotic initial state. + amplitude = 0.10 # Increased from 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Stage 1: Vortex Disruption (NEW) + # This new stage applies a rotational force to violently break the grid symmetry, + # helping the system escape the initial ordered local minimum. + vortex_iters = 75 + vortex_step_size = 0.002 + vortex_center = np.array([0.5, 0.5]) + vortex_strength = 0.008 + vortex_repulsion_strength = 0.015 # Add repulsion to prevent collapse + vortex_boundary_strength = 0.1 + vortex_repulsion_threshold = 0.20 + vortex_boundary_margin = 0.04 + + for _ in range(vortex_iters): + forces = np.zeros_like(centers) + for i in range(n): + # Rotational force + vec_from_center = centers[i] - vortex_center + forces[i] += vortex_strength * np.array([-vec_from_center[1], vec_from_center[0]]) + # Repulsion force + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < vortex_repulsion_threshold: + force_mag = vortex_repulsion_strength * (vortex_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary forces + for i in range(n): + x, y = centers[i] + if x < vortex_boundary_margin: forces[i, 0] += vortex_boundary_strength * (vortex_boundary_margin - x) + if x > 1 - vortex_boundary_margin: forces[i, 0] -= vortex_boundary_strength * (x - (1 - vortex_boundary_margin)) + if y < vortex_boundary_margin: forces[i, 1] += vortex_boundary_strength * (y - (1 - vortex_boundary_margin)) + if y > 1 - vortex_boundary_margin: forces[i, 1] -= vortex_boundary_strength * (y - (1 - vortex_boundary_margin)) + centers += vortex_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + + # 5. Stage 2: High-Energy Exploration ("Shaking") + # This stage now operates on a more chaotic configuration from the vortex. + exploration_iters = 350 # Increased from 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 # Increased from 0.02 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + exploration_boundary_margin = 0.04 # Initial broader margin + + centers = _relax_stage(centers, n, exploration_iters, exploration_step_size, + exploration_repulsion_strength, exploration_boundary_strength, + exploration_repulsion_threshold, exploration_boundary_margin) + + # 6. Stage 3: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 600 # Increased from 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 # Increased from 0.008 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + refinement_boundary_margin = 0.02 # Tighter margin for finer packing against boundaries + + centers = _relax_stage(centers, n, refinement_iters, refinement_step_size, + refinement_repulsion_strength, refinement_boundary_strength, + refinement_repulsion_threshold, refinement_boundary_margin) + + # 7. Stage 4: Ultra-Low-Energy Annealing ("Polishing") + # Final micro-adjustments with very weak forces and many iterations for precise packing. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + annealing_boundary_margin = 0.01 # Even tighter margin for final precision + + centers = _relax_stage(centers, n, annealing_iters, annealing_step_size, + annealing_repulsion_strength, annealing_boundary_strength, + annealing_repulsion_threshold, annealing_boundary_margin) + + # 8. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a6ed3c55f31fa672e2b059c3095e9d451a614b9 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..a81e3191e60d480e3adc242d6a8c0b9763d7b2ee --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": false, + "error": "name 'tangential_scalar_tangential' is not defined" +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..3092f3d31ebe1edf0047006df5458ab88d3d3c73 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/job_log.out @@ -0,0 +1,14 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_106/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_106/results +Evaluation error: name 'tangential_scalar_tangential' is not defined +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/metrics.json +Evaluation or Validation failed: name 'tangential_scalar_tangential' is not defined +Metrics: + combined_score: 0.0 + execution_time_mean: 0.0 + execution_time_std: 0.0 + num_successful_runs: 0 + num_valid_runs: 0 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..fec2021a6a036637c9d3049ae9778c77cef78421 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_106/results/metrics.json @@ -0,0 +1,9 @@ +{ + "combined_score": 0.0, + "execution_time_mean": 0.0, + "execution_time_std": 0.0, + "num_successful_runs": 0, + "num_valid_runs": 0, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad3962a1303783b8ac0ad6f937a56c0955855011 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..7c760ccdfd04073aec35d0a66196633a72916d3f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/edit.diff @@ -0,0 +1,224 @@ +--- a/original.py ++++ b/original.py +@@ -1,217 +1,217 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by combining a + Gaussian-deformed grid initialization with a two-stage adaptive + force-directed relaxation to optimize the final positions. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in an asymmetric void and deform the grid. + # An off-center void breaks the initial symmetry, which helps avoid + # suboptimal local minima and leads to a denser packing. + # This position is inspired by a previous high-scoring configuration. + void_center = np.array([0.4, 0.2]) +- amplitude = 0.04 # Displacement magnitude, matched to inspiration program ++ amplitude = 0.06 # Reverted to 0.06 for a stronger initial push (like prior 1.98 programs) + sigma = 0.15 # Range of the repulsive force + + # Using a vectorized approach for displacement calculation + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 3. Two-Stage Adaptive Force-Directed Relaxation (Crossover from other prior programs) + # This step is crucial. It takes the rough initial placement and lets the circles + # settle into a much more efficient, relaxed packing. + + # Stage-specific parameters are introduced to progressively tighten the packing. + + # Stage 1: Exploration - Broad adjustments +- exploration_iters = 100 ++ exploration_iters = 300 # Increased iterations for better initial rearrangement + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + exploration_repulsion_threshold = 0.19 # Larger threshold for broad interaction + exploration_boundary_margin = 0.04 # Standard margin + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning +- refinement_iters = 150 ++ refinement_iters = 500 # Increased iterations for better convergence + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + refinement_repulsion_threshold = 0.18 # Tighter threshold for precise packing + refinement_boundary_margin = 0.02 # Smaller margin to get closer to edges + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Ultra-Low-Energy Annealing - Final Polish + # Applies very gentle forces over many iterations to push circles into + # their absolute tightest configuration. +- annealing_iters = 250 ++ annealing_iters = 800 # Increased iterations for maximum convergence and polish + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 + annealing_boundary_strength = 0.005 + annealing_repulsion_threshold = 0.175 # Very tight threshold for final packing + annealing_boundary_margin = 0.01 # Extremely small margin to push circles to the edge + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 4. Compute maximum valid radii for the final, relaxed configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/main.py new file mode 100644 index 0000000000000000000000000000000000000000..484c5b44f1ca1cdbc04081be0231d101e685689f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/main.py @@ -0,0 +1,217 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by combining a + Gaussian-deformed grid initialization with a two-stage adaptive + force-directed relaxation to optimize the final positions. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in an asymmetric void and deform the grid. + # An off-center void breaks the initial symmetry, which helps avoid + # suboptimal local minima and leads to a denser packing. + # This position is inspired by a previous high-scoring configuration. + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 # Reverted to 0.06 for a stronger initial push (like prior 1.98 programs) + sigma = 0.15 # Range of the repulsive force + + # Using a vectorized approach for displacement calculation + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 3. Two-Stage Adaptive Force-Directed Relaxation (Crossover from other prior programs) + # This step is crucial. It takes the rough initial placement and lets the circles + # settle into a much more efficient, relaxed packing. + + # Stage-specific parameters are introduced to progressively tighten the packing. + + # Stage 1: Exploration - Broad adjustments + exploration_iters = 300 # Increased iterations for better initial rearrangement + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + exploration_repulsion_threshold = 0.19 # Larger threshold for broad interaction + exploration_boundary_margin = 0.04 # Standard margin + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning + refinement_iters = 500 # Increased iterations for better convergence + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + refinement_repulsion_threshold = 0.18 # Tighter threshold for precise packing + refinement_boundary_margin = 0.02 # Smaller margin to get closer to edges + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Ultra-Low-Energy Annealing - Final Polish + # Applies very gentle forces over many iterations to push circles into + # their absolute tightest configuration. + annealing_iters = 800 # Increased iterations for maximum convergence and polish + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 + annealing_boundary_strength = 0.005 + annealing_repulsion_threshold = 0.175 # Very tight threshold for final packing + annealing_boundary_margin = 0.01 # Extremely small margin to push circles to the edge + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 4. Compute maximum valid radii for the final, relaxed configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/original.py new file mode 100644 index 0000000000000000000000000000000000000000..64d056753dbfe71cb4a468e1d487b7561031aa90 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/original.py @@ -0,0 +1,217 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by combining a + Gaussian-deformed grid initialization with a two-stage adaptive + force-directed relaxation to optimize the final positions. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in an asymmetric void and deform the grid. + # An off-center void breaks the initial symmetry, which helps avoid + # suboptimal local minima and leads to a denser packing. + # This position is inspired by a previous high-scoring configuration. + void_center = np.array([0.4, 0.2]) + amplitude = 0.04 # Displacement magnitude, matched to inspiration program + sigma = 0.15 # Range of the repulsive force + + # Using a vectorized approach for displacement calculation + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 3. Two-Stage Adaptive Force-Directed Relaxation (Crossover from other prior programs) + # This step is crucial. It takes the rough initial placement and lets the circles + # settle into a much more efficient, relaxed packing. + + # Stage-specific parameters are introduced to progressively tighten the packing. + + # Stage 1: Exploration - Broad adjustments + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + exploration_repulsion_threshold = 0.19 # Larger threshold for broad interaction + exploration_boundary_margin = 0.04 # Standard margin + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + refinement_repulsion_threshold = 0.18 # Tighter threshold for precise packing + refinement_boundary_margin = 0.02 # Smaller margin to get closer to edges + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Ultra-Low-Energy Annealing - Final Polish + # Applies very gentle forces over many iterations to push circles into + # their absolute tightest configuration. + annealing_iters = 250 + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 + annealing_boundary_strength = 0.005 + annealing_repulsion_threshold = 0.175 # Very tight threshold for final packing + annealing_boundary_margin = 0.01 # Extremely small margin to push circles to the edge + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 4. Compute maximum valid radii for the final, relaxed configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..ffe822214b5e1336efda93265180e691ee69a36a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_107/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_107/results +Run 1/1 completed in 1.69 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9822849103424658 + public: {'centers_str': ' centers[0] = (0.0933, 0.0980)\n centers[1] = (0.2729, 0.0723)\n centers[2] = (0.5271, 0.0723)\n centers[3] = (0.7067, 0.0980)\n centers[4] = (0.9002, 0.1000)\n centers[5] = (0.0933, 0.3020)\n centers[6] = (0.2728, 0.3272)\n centers[7] = (0.5272, 0.3272)\n centers[8] = (0.7067, 0.3020)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0992, 0.5008)\n centers[11] = (0.2980, 0.5067)\n centers[12] = (0.5020, 0.5067)\n centers[13] = (0.7008, 0.5008)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7002)\n centers[17] = (0.5000, 0.7002)\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.4000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9822849103424658} + visualization_path: + execution_time_mean: 1.691146345809102 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..bea0334780b3680c1d7170727182a9539c6ea2ae --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9822849103424658, + "public": { + "centers_str": " centers[0] = (0.0933, 0.0980)\n centers[1] = (0.2729, 0.0723)\n centers[2] = (0.5271, 0.0723)\n centers[3] = (0.7067, 0.0980)\n centers[4] = (0.9002, 0.1000)\n centers[5] = (0.0933, 0.3020)\n centers[6] = (0.2728, 0.3272)\n centers[7] = (0.5272, 0.3272)\n centers[8] = (0.7067, 0.3020)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0992, 0.5008)\n centers[11] = (0.2980, 0.5067)\n centers[12] = (0.5020, 0.5067)\n centers[13] = (0.7008, 0.5008)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7002)\n centers[17] = (0.5000, 0.7002)\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.4000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9822849103424658 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_107/results/packing_viz.png", + "execution_time_mean": 1.691146345809102, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..c05b016baf9177458939e236a3a5a7814d22c80d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_107/search_replace.txt @@ -0,0 +1,86 @@ +revert_amplitude_and_increase_iterations +The visualization shows a sum of radii of 1.9767, which is slightly lower than previous high-scoring programs (1.98). The central region, especially around (0.4, 0.2), is not optimally packed; a very large circle occupies the void, surrounded by tiny circles. This suggests that the initial perturbation might not be strong enough or the relaxation stages are not given enough time to fully rearrange. + +Comparing with previous high-scoring programs: +1. **Gaussian Push Amplitude**: The current program uses `amplitude = 0.04` for the initial Gaussian push. Previous programs achieving 1.98 used `amplitude = 0.06`. A larger amplitude creates a more pronounced initial void, which, counter-intuitively, can give the subsequent relaxation more space to rearrange the circles into a denser, non-grid-like pattern, including a better distribution within the void. Reverting to `0.06` should enhance this initial dis-ordering. +2. **Iteration Counts**: The current program uses `exploration_iters = 100`, `refinement_iters = 150`, and `annealing_iters = 250`. In contrast, the previous 1.98 programs used significantly higher iteration counts: `exploration_iters = 300`, `refinement_iters = 500`, and `annealing_iters = 800`. Force-directed relaxation methods often require a substantial number of iterations to converge to a good local optimum, especially in later, weaker stages. Increasing these iteration counts will allow the forces to propagate more thoroughly and enable the circles to settle into tighter and more stable configurations. + +These changes aim to provide a more aggressive initial perturbation and then give the system ample time to explore and refine the packing, addressing the visually inefficient central area and the lingering grid-like structure. + +<<<<<<< SEARCH + void_center = np.array([0.4, 0.2]) + amplitude = 0.04 # Displacement magnitude, matched to inspiration program + sigma = 0.15 # Range of the repulsive force + + # Using a vectorized approach for displacement calculation + displacements = base_centers_25 - void_center +======= + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 # Reverted to 0.06 for a stronger initial push (like prior 1.98 programs) + sigma = 0.15 # Range of the repulsive force + + # Using a vectorized approach for displacement calculation + displacements = base_centers_25 - void_center +>>>>>>> REPLACE + + +<<<<<<< SEARCH + # Stage 1: Exploration - Broad adjustments + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + exploration_repulsion_threshold = 0.19 # Larger threshold for broad interaction + exploration_boundary_margin = 0.04 # Standard margin +======= + # Stage 1: Exploration - Broad adjustments + exploration_iters = 300 # Increased iterations for better initial rearrangement + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + exploration_repulsion_threshold = 0.19 # Larger threshold for broad interaction + exploration_boundary_margin = 0.04 # Standard margin +>>>>>>> REPLACE + + +<<<<<<< SEARCH + # Stage 2: Refinement - Fine-tuning + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + refinement_repulsion_threshold = 0.18 # Tighter threshold for precise packing + refinement_boundary_margin = 0.02 # Smaller margin to get closer to edges +======= + # Stage 2: Refinement - Fine-tuning + refinement_iters = 500 # Increased iterations for better convergence + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + refinement_repulsion_threshold = 0.18 # Tighter threshold for precise packing + refinement_boundary_margin = 0.02 # Smaller margin to get closer to edges +>>>>>>> REPLACE + + +<<<<<<< SEARCH + # Stage 3: Ultra-Low-Energy Annealing - Final Polish + # Applies very gentle forces over many iterations to push circles into + # their absolute tightest configuration. + annealing_iters = 250 + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 + annealing_boundary_strength = 0.005 + annealing_repulsion_threshold = 0.175 # Very tight threshold for final packing + annealing_boundary_margin = 0.01 # Extremely small margin to push circles to the edge +======= + # Stage 3: Ultra-Low-Energy Annealing - Final Polish + # Applies very gentle forces over many iterations to push circles into + # their absolute tightest configuration. + annealing_iters = 800 # Increased iterations for maximum convergence and polish + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 + annealing_boundary_strength = 0.005 + annealing_repulsion_threshold = 0.175 # Very tight threshold for final packing + annealing_boundary_margin = 0.01 # Extremely small margin to push circles to the edge +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fa64eb1e4ed3e319fef935b8b78c9f4703b9322b Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..b4dbd3a1abbeb0544149d68690b655cecc862b61 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_108/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_108/results +Run 1/1 completed in 2.21 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.7856518689457528 + public: {'centers_str': ' centers[0] = (0.1364, 0.0566)\n centers[1] = (0.3210, 0.0478)\n centers[2] = (0.5728, 0.0751)\n centers[3] = (0.7503, 0.1232)\n centers[4] = (0.9421, 0.1456)\n centers[5] = (0.1144, 0.2585)\n centers[6] = (0.2928, 0.3036)\n centers[7] = (0.5456, 0.3310)\n centers[8] = (0.7286, 0.3251)\n centers[9] = (0.9205, 0.3444)\n centers[10] = (0.1013, 0.4576)\n centers[11] = (0.2988, 0.4866)\n centers[12] = (0.5005, 0.5085)\n centers[13] = (0.6995, 0.5224)\n centers[14] = (0.8978, 0.5431)\n centers[15] = (0.0807, 0.6559)\n centers[16] = (0.2794, 0.6785)\n centers[17] = (0.4783, 0.7001)\n centers[18] = (0.6773, 0.7205)\n centers[19] = (0.8761, 0.7420)\n centers[20] = (0.0592, 0.8546)\n centers[21] = (0.2580, 0.8762)\n centers[22] = (0.4569, 0.8978)\n centers[23] = (0.6557, 0.9192)\n centers[24] = (0.8546, 0.9408)\n centers[25] = (0.4329, 0.1907)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.7856518689457528} + visualization_path: + execution_time_mean: 2.2059786110185087 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..b6f3d5edd03ce60b79f628964919879631c4ae5d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.7856518689457528, + "public": { + "centers_str": " centers[0] = (0.1364, 0.0566)\n centers[1] = (0.3210, 0.0478)\n centers[2] = (0.5728, 0.0751)\n centers[3] = (0.7503, 0.1232)\n centers[4] = (0.9421, 0.1456)\n centers[5] = (0.1144, 0.2585)\n centers[6] = (0.2928, 0.3036)\n centers[7] = (0.5456, 0.3310)\n centers[8] = (0.7286, 0.3251)\n centers[9] = (0.9205, 0.3444)\n centers[10] = (0.1013, 0.4576)\n centers[11] = (0.2988, 0.4866)\n centers[12] = (0.5005, 0.5085)\n centers[13] = (0.6995, 0.5224)\n centers[14] = (0.8978, 0.5431)\n centers[15] = (0.0807, 0.6559)\n centers[16] = (0.2794, 0.6785)\n centers[17] = (0.4783, 0.7001)\n centers[18] = (0.6773, 0.7205)\n centers[19] = (0.8761, 0.7420)\n centers[20] = (0.0592, 0.8546)\n centers[21] = (0.2580, 0.8762)\n centers[22] = (0.4569, 0.8978)\n centers[23] = (0.6557, 0.9192)\n centers[24] = (0.8546, 0.9408)\n centers[25] = (0.4329, 0.1907)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.7856518689457528 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_108/results/packing_viz.png", + "execution_time_mean": 2.2059786110185087, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48cd954aff9e0ac71b56bd596e7923cded06b0ba Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..6b40b578292b32770eff03ec830f99c4fa5d0fd2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_109/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_109/results +Run 1/1 completed in 1.63 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9808569554223658 + 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} + private: {'reported_sum_of_radii': 1.9808569554223658} + visualization_path: + execution_time_mean: 1.6307015819475055 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..7846a0922d68db800b40828a37554315b57025e4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9808569554223658, + "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 + }, + "private": { + "reported_sum_of_radii": 1.9808569554223658 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_109/results/packing_viz.png", + "execution_time_mean": 1.6307015819475055, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad4a8f7056a7a6e0815bf3657a9f3cbfb9b68478 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..365170a7b3f9257b22eda92e6521bfb83585d71d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/edit.diff @@ -0,0 +1,152 @@ +--- a/original.py ++++ b/original.py +@@ -1,109 +1,102 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + +- # A more symmetric and compact grid layout inspired by dense packings. +- # The previous layout was asymmetric ([5,6,5,6,4]) and had poor vertical spacing. +- num_rows = 5 +- # This row count distribution is symmetric and places more circles in the center. +- row_counts = [5, 5, 6, 5, 5] # Total: 5+5+6+5+5 = 26 circles ++ # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), ++ # which provides a very strong and dense foundation. ++ # The 26th circle is then placed in a central interstitial void. + +- # Use tighter vertical packing. The previous method left large gaps (1/6) at top/bottom. +- # This linspace packs rows from y=0.1 to y=0.9, consistent with a radius of 0.1 for a 5x5 grid. +- y_coords = np.linspace(0.1, 0.9, num_rows) ++ # 1. Place 25 circles in a 5x5 grid. ++ # This is the known optimal packing for 25 equal circles. ++ x_coords_5 = np.linspace(0.1, 0.9, 5) ++ y_coords_5 = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords_5, y_coords_5) ++ centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + +- # Margin for x coordinates, consistent with y_coords margins. +- margin = 0.1 +- +- idx = 0 +- for r_idx, count in enumerate(row_counts): +- y = y_coords[r_idx] +- +- # Simplified staggering logic. +- # Odd rows are shifted to sit in the gaps of even rows. +- if r_idx % 2 == 0: # Even rows (0, 2, 4) +- # Place circles edge-to-edge within the margins +- x_coords = np.linspace(margin, 1.0 - margin, count) +- else: # Odd rows (1, 3) are staggered +- # Create space at the ends to shift the circles. +- # linspace over (count+2) points and skipping the first and last +- # achieves a simple and effective stagger. +- x_coords = np.linspace(margin, 1.0 - margin, count + 2)[1:-1] +- +- for x in x_coords: +- if idx < n: +- centers[idx] = [x, y] +- idx += 1 +- +- # The placement logic naturally keeps centers within the square. +- # No clipping is necessary, as radii calculation correctly handles boundaries. ++ # 2. Place the 26th circle in a promising interstitial position. ++ # The voids in a 5x5 grid are at positions like (0.2, 0.2), (0.2, 0.4), etc. ++ # Placing it at (0.4, 0.4) puts it in a central void, surrounded by ++ # circles at (0.3, 0.3), (0.5, 0.3), (0.3, 0.5), and (0.5, 0.5). ++ # This should allow it to acquire a small radius while minimally ++ # disturbing the main grid, leading to a high total sum. ++ centers[25] = [0.4, 0.4] + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. ++ such that they don't overlap and stay within the unit square. This version ++ iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] +- # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + +- # Then, limit by distance to other circles +- # Each pair of circles with centers at distance d can have +- # sum of radii at most d to avoid overlap +- for i in range(n): +- for j in range(i + 1, n): +- dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) ++ # Iteratively limit by distance to other circles, allowing constraints to propagate ++ for _ in range(300): # Iterate to ensure convergence ++ changes_made = False ++ for i in range(n): ++ for j in range(i + 1, n): ++ dist = np.linalg.norm(centers[i] - centers[j]) + +- # If current radii would cause overlap +- if radii[i] + radii[j] > dist: +- # Scale both radii proportionally +- scale = dist / (radii[i] + radii[j]) +- radii[i] *= scale +- radii[j] *= scale ++ # If current radii cause overlap ++ if radii[i] + radii[j] > dist: ++ sum_r = radii[i] + radii[j] ++ if sum_r > 1e-9: # Avoid division by zero for coincident centers ++ # Scale both radii proportionally to resolve overlap ++ scale = dist / sum_r ++ ri_new = radii[i] * scale ++ rj_new = radii[j] * scale ++ ++ # Check for significant change to set the flag ++ if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: ++ radii[i] = ri_new ++ radii[j] = rj_new ++ changes_made = True ++ if not changes_made: ++ break # Exit early if the configuration is stable + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/main.py new file mode 100644 index 0000000000000000000000000000000000000000..0754cfae53d5d2ac3c9ef87ff9919f5558aef502 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/main.py @@ -0,0 +1,102 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a promising interstitial position. + # The voids in a 5x5 grid are at positions like (0.2, 0.2), (0.2, 0.4), etc. + # Placing it at (0.4, 0.4) puts it in a central void, surrounded by + # circles at (0.3, 0.3), (0.5, 0.3), (0.3, 0.5), and (0.5, 0.5). + # This should allow it to acquire a small radius while minimally + # disturbing the main grid, leading to a high total sum. + centers[25] = [0.4, 0.4] + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/original.py new file mode 100644 index 0000000000000000000000000000000000000000..64494262aa335723d036acc4da1821ec21a083be --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/original.py @@ -0,0 +1,109 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # A more symmetric and compact grid layout inspired by dense packings. + # The previous layout was asymmetric ([5,6,5,6,4]) and had poor vertical spacing. + num_rows = 5 + # This row count distribution is symmetric and places more circles in the center. + row_counts = [5, 5, 6, 5, 5] # Total: 5+5+6+5+5 = 26 circles + + # Use tighter vertical packing. The previous method left large gaps (1/6) at top/bottom. + # This linspace packs rows from y=0.1 to y=0.9, consistent with a radius of 0.1 for a 5x5 grid. + y_coords = np.linspace(0.1, 0.9, num_rows) + + # Margin for x coordinates, consistent with y_coords margins. + margin = 0.1 + + idx = 0 + for r_idx, count in enumerate(row_counts): + y = y_coords[r_idx] + + # Simplified staggering logic. + # Odd rows are shifted to sit in the gaps of even rows. + if r_idx % 2 == 0: # Even rows (0, 2, 4) + # Place circles edge-to-edge within the margins + x_coords = np.linspace(margin, 1.0 - margin, count) + else: # Odd rows (1, 3) are staggered + # Create space at the ends to shift the circles. + # linspace over (count+2) points and skipping the first and last + # achieves a simple and effective stagger. + x_coords = np.linspace(margin, 1.0 - margin, count + 2)[1:-1] + + for x in x_coords: + if idx < n: + centers[idx] = [x, y] + idx += 1 + + # The placement logic naturally keeps centers within the square. + # No clipping is necessary, as radii calculation correctly handles boundaries. + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..7faf1f0858014ae2812d4eb0919e37939b0322bf --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_11/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_11/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9200929312704162 + 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.4000, 0.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9200929312704162} + visualization_path: + execution_time_mean: 0.0023727440275251865 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..6487fa7105959d1e0d64ba4038aa73e775c7e7a8 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9200929312704162, + "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.4000, 0.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9200929312704162 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_11/results/packing_viz.png", + "execution_time_mean": 0.0023727440275251865, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..b2811738a4dd0f08b9e6c02aa31fc39322b3e82f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_11/search_replace.txt @@ -0,0 +1,159 @@ + +grid_plus_interstitial_and_iterative_radii + + + +The current circle arrangement, based on a `[5, 5, 6, 5, 5]` staggered grid, is highly inefficient. As seen in the visualization, the staggering logic is flawed, causing circles in the central rows to be severely compressed, resulting in near-zero radii and large empty spaces. The overall sum of radii (1.51) is very poor. + +This proposal implements a two-part major improvement: + +1. **New Packing Strategy in `construct_packing`**: The flawed `[5,5,6,5,5]` layout is replaced by a much stronger foundation: the optimal `5x5` grid for 25 circles. This grid, with centers from 0.1 to 0.9, creates a dense and stable base. The 26th circle is then strategically placed in a central interstitial void at `(0.4, 0.4)`. This position is equidistant from four circles of the main grid, allowing it to find a stable position without catastrophically collapsing the entire structure. This "grid-plus-one" approach is a classic technique in constructive circle packing. + +2. **Iterative Radius Calculation in `compute_max_radii`**: The original single-pass radius calculation is incorrect and can severely underestimate the possible radii. A single pass fails to propagate constraints globally. It is replaced with a robust iterative algorithm. This new function repeatedly scans for and resolves overlaps by proportionally scaling radii until the arrangement converges to a stable, non-overlapping state. This is crucial for correctly evaluating any given set of centers, especially a more complex one like the proposed "grid-plus-one". + +Together, these changes provide a much more promising geometric arrangement and the correct mechanism to evaluate its potential, aiming for a significant increase in the total sum of radii. + + + +<<<<<<< SEARCH + # A more symmetric and compact grid layout inspired by dense packings. + # The previous layout was asymmetric ([5,6,5,6,4]) and had poor vertical spacing. + num_rows = 5 + # This row count distribution is symmetric and places more circles in the center. + row_counts = [5, 5, 6, 5, 5] # Total: 5+5+6+5+5 = 26 circles + + # Use tighter vertical packing. The previous method left large gaps (1/6) at top/bottom. + # This linspace packs rows from y=0.1 to y=0.9, consistent with a radius of 0.1 for a 5x5 grid. + y_coords = np.linspace(0.1, 0.9, num_rows) + + # Margin for x coordinates, consistent with y_coords margins. + margin = 0.1 + + idx = 0 + for r_idx, count in enumerate(row_counts): + y = y_coords[r_idx] + + # Simplified staggering logic. + # Odd rows are shifted to sit in the gaps of even rows. + if r_idx % 2 == 0: # Even rows (0, 2, 4) + # Place circles edge-to-edge within the margins + x_coords = np.linspace(margin, 1.0 - margin, count) + else: # Odd rows (1, 3) are staggered + # Create space at the ends to shift the circles. + # linspace over (count+2) points and skipping the first and last + # achieves a simple and effective stagger. + x_coords = np.linspace(margin, 1.0 - margin, count + 2)[1:-1] + + for x in x_coords: + if idx < n: + centers[idx] = [x, y] + idx += 1 + + # The placement logic naturally keeps centers within the square. + # No clipping is necessary, as radii calculation correctly handles boundaries. +======= + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a promising interstitial position. + # The voids in a 5x5 grid are at positions like (0.2, 0.2), (0.2, 0.4), etc. + # Placing it at (0.4, 0.4) puts it in a central void, surrounded by + # circles at (0.3, 0.3), (0.5, 0.3), (0.3, 0.5), and (0.5, 0.5). + # This should allow it to acquire a small radius while minimally + # disturbing the main grid, leading to a high total sum. + centers[25] = [0.4, 0.4] +>>>>>>> REPLACE + + +<<<<<<< SEARCH +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii +======= +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..53811db737dada0d25481d078be73b13e0eb5332 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..eea4d4799fa099438c91168440c06196dde91600 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": false, + "error": "name 'tangential_scalar' is not defined" +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..66f72e64d5dc8d357462f75fdaa5271477527380 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/job_log.out @@ -0,0 +1,14 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_110/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_110/results +Evaluation error: name 'tangential_scalar' is not defined +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/metrics.json +Evaluation or Validation failed: name 'tangential_scalar' is not defined +Metrics: + combined_score: 0.0 + execution_time_mean: 0.0 + execution_time_std: 0.0 + num_successful_runs: 0 + num_valid_runs: 0 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..fec2021a6a036637c9d3049ae9778c77cef78421 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_110/results/metrics.json @@ -0,0 +1,9 @@ +{ + "combined_score": 0.0, + "execution_time_mean": 0.0, + "execution_time_std": 0.0, + "num_successful_runs": 0, + "num_valid_runs": 0, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1298c71c9f6943f5abdfce34a309a2aec230eee9 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..519a30f654884c86b7846ba81d3d5a214965fc42 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/job_log.err @@ -0,0 +1,15 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_112/main.py:84: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_112/main.py:107: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_112/main.py:130: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..2f028ca287efb2fb98182cac57c523248f7fdca2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_112/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_112/results +Run 1/1 completed in 0.12 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9821771452614922 + public: {'centers_str': ' centers[0] = (0.0932, 0.0980)\n centers[1] = (0.2729, 0.0722)\n centers[2] = (0.5271, 0.0722)\n centers[3] = (0.7066, 0.0980)\n centers[4] = (0.9004, 0.1000)\n centers[5] = (0.0932, 0.3019)\n centers[6] = (0.2729, 0.3271)\n centers[7] = (0.5271, 0.3271)\n centers[8] = (0.7066, 0.3019)\n centers[9] = (0.9004, 0.3000)\n centers[10] = (0.0992, 0.5008)\n centers[11] = (0.2981, 0.5066)\n centers[12] = (0.5019, 0.5066)\n centers[13] = (0.7008, 0.5008)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7004)\n centers[17] = (0.5000, 0.7004)\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.4000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9821771452614922} + visualization_path: + execution_time_mean: 0.11643417412415147 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..b06af8ceb8cf33a6fb3a009c1ff0fdaae969a792 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9821771452614922, + "public": { + "centers_str": " centers[0] = (0.0932, 0.0980)\n centers[1] = (0.2729, 0.0722)\n centers[2] = (0.5271, 0.0722)\n centers[3] = (0.7066, 0.0980)\n centers[4] = (0.9004, 0.1000)\n centers[5] = (0.0932, 0.3019)\n centers[6] = (0.2729, 0.3271)\n centers[7] = (0.5271, 0.3271)\n centers[8] = (0.7066, 0.3019)\n centers[9] = (0.9004, 0.3000)\n centers[10] = (0.0992, 0.5008)\n centers[11] = (0.2981, 0.5066)\n centers[12] = (0.5019, 0.5066)\n centers[13] = (0.7008, 0.5008)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7004)\n centers[17] = (0.5000, 0.7004)\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.4000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9821771452614922 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_112/results/packing_viz.png", + "execution_time_mean": 0.11643417412415147, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..564fc1bec7836e58a56866279a0f3134826da98d Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..52c38530da70e5b67880fddbb8a6f2fa99e16887 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/edit.diff @@ -0,0 +1,257 @@ +--- a/original.py ++++ b/original.py +@@ -1,197 +1,182 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Using (0.4, 0.2) breaks initial symmetry, encouraging unique, denser packings. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. +- deformed_centers_25 = np.copy(base_centers_25) +- + # Increased amplitude to create a larger initial void. +- amplitude = 0.06 ++ amplitude = 0.08 + sigma = 0.15 + +- for i in range(25): +- pos_vector = base_centers_25[i] - void_center +- dist_sq = np.sum(pos_vector**2) +- push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) +- if np.linalg.norm(pos_vector) > 1e-9: +- direction = pos_vector / np.linalg.norm(pos_vector) +- displacement = direction * push_magnitude +- deformed_centers_25[i] += displacement ++ # Vectorized Gaussian push for efficiency and clarity ++ displacements = base_centers_25 - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ mask = distances > 1e-9 ++ ++ push_magnitudes = np.zeros(25) ++ if np.any(mask): ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ # Normalize displacement vectors ++ displacements[mask] /= distances[mask, np.newaxis] ++ ++ deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # Common boundary margin for all stages + boundary_margin = 0.04 + +- # 4. Stage 1: High-Energy Exploration ("Shaking") +- # Increased iterations and strength to break the grid structure more effectively. +- exploration_iters = 300 ++ # 4. Stage 1: High-Energy Exploration ("Shaking") - VECTORIZED ++ # Now vectorized, we can use more iterations and stronger forces to shatter the grid. ++ exploration_iters = 800 + exploration_step_size = 0.003 +- exploration_repulsion_strength = 0.025 +- exploration_boundary_strength = 0.1 +- exploration_repulsion_threshold = 0.20 ++ exploration_repulsion_strength = 0.03 ++ exploration_boundary_strength = 0.15 ++ exploration_repulsion_threshold = 0.21 + + for _ in range(exploration_iters): +- forces = np.zeros_like(centers) +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < exploration_repulsion_threshold: +- force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist +- force_vec = force_mag * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- for i in range(n): +- x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) ++ diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] ++ dists = np.linalg.norm(diff, axis=2) ++ mask = (dists > 1e-9) & (dists < exploration_repulsion_threshold) ++ force_scalar = np.zeros_like(dists) ++ force_scalar[mask] = exploration_repulsion_strength * (exploration_repulsion_threshold - dists[mask]) / dists[mask] ++ force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ forces = np.sum(force_vectors, axis=1) ++ forces[:, 0] += exploration_boundary_strength * np.maximum(0, boundary_margin - centers[:, 0]) ++ forces[:, 0] -= exploration_boundary_strength * np.maximum(0, centers[:, 0] - (1 - boundary_margin)) ++ forces[:, 1] += exploration_boundary_strength * np.maximum(0, boundary_margin - centers[:, 1]) ++ forces[:, 1] -= exploration_boundary_strength * np.maximum(0, centers[:, 1] - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + +- # 5. Stage 2: Low-Energy Refinement ("Settling") +- # A longer settling period with moderate forces to find a good basin of attraction. +- refinement_iters = 500 ++ # 5. Stage 2: Low-Energy Refinement ("Settling") - VECTORIZED ++ refinement_iters = 1000 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 +- refinement_boundary_strength = 0.04 ++ refinement_boundary_strength = 0.05 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): +- forces = np.zeros_like(centers) +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < refinement_repulsion_threshold: +- force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist +- force_vec = force_mag * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- for i in range(n): +- x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) ++ diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] ++ dists = np.linalg.norm(diff, axis=2) ++ mask = (dists > 1e-9) & (dists < refinement_repulsion_threshold) ++ force_scalar = np.zeros_like(dists) ++ force_scalar[mask] = refinement_repulsion_strength * (refinement_repulsion_threshold - dists[mask]) / dists[mask] ++ force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ forces = np.sum(force_vectors, axis=1) ++ forces[:, 0] += refinement_boundary_strength * np.maximum(0, boundary_margin - centers[:, 0]) ++ forces[:, 0] -= refinement_boundary_strength * np.maximum(0, centers[:, 0] - (1 - boundary_margin)) ++ forces[:, 1] += refinement_boundary_strength * np.maximum(0, boundary_margin - centers[:, 1]) ++ forces[:, 1] -= refinement_boundary_strength * np.maximum(0, centers[:, 1] - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + +- # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") +- # A new stage for final micro-adjustments with very weak forces and many iterations. +- annealing_iters = 800 ++ # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") - VECTORIZED ++ annealing_iters = 1500 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + + for _ in range(annealing_iters): +- forces = np.zeros_like(centers) +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < annealing_repulsion_threshold: +- force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist +- force_vec = force_mag * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- for i in range(n): +- x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) ++ diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] ++ dists = np.linalg.norm(diff, axis=2) ++ mask = (dists > 1e-9) & (dists < annealing_repulsion_threshold) ++ force_scalar = np.zeros_like(dists) ++ force_scalar[mask] = annealing_repulsion_strength * (annealing_repulsion_threshold - dists[mask]) / dists[mask] ++ force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ forces = np.sum(force_vectors, axis=1) ++ forces[:, 0] += annealing_boundary_strength * np.maximum(0, boundary_margin - centers[:, 0]) ++ forces[:, 0] -= annealing_boundary_strength * np.maximum(0, centers[:, 0] - (1 - boundary_margin)) ++ forces[:, 1] += annealing_boundary_strength * np.maximum(0, boundary_margin - centers[:, 1]) ++ forces[:, 1] -= annealing_boundary_strength * np.maximum(0, centers[:, 1] - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries using vectorized operation. + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations and tight tolerance ensures convergence. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/main.py new file mode 100644 index 0000000000000000000000000000000000000000..05c6a662447edd1dd08a14f9e26f6edbcd760a4c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/main.py @@ -0,0 +1,182 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Using (0.4, 0.2) breaks initial symmetry, encouraging unique, denser packings. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # Increased amplitude to create a larger initial void. + amplitude = 0.08 + sigma = 0.15 + + # Vectorized Gaussian push for efficiency and clarity + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + # Normalize displacement vectors + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # Common boundary margin for all stages + boundary_margin = 0.04 + + # 4. Stage 1: High-Energy Exploration ("Shaking") - VECTORIZED + # Now vectorized, we can use more iterations and stronger forces to shatter the grid. + exploration_iters = 800 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.03 + exploration_boundary_strength = 0.15 + exploration_repulsion_threshold = 0.21 + + for _ in range(exploration_iters): + diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + mask = (dists > 1e-9) & (dists < exploration_repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = exploration_repulsion_strength * (exploration_repulsion_threshold - dists[mask]) / dists[mask] + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + forces[:, 0] += exploration_boundary_strength * np.maximum(0, boundary_margin - centers[:, 0]) + forces[:, 0] -= exploration_boundary_strength * np.maximum(0, centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += exploration_boundary_strength * np.maximum(0, boundary_margin - centers[:, 1]) + forces[:, 1] -= exploration_boundary_strength * np.maximum(0, centers[:, 1] - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") - VECTORIZED + refinement_iters = 1000 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.05 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + mask = (dists > 1e-9) & (dists < refinement_repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = refinement_repulsion_strength * (refinement_repulsion_threshold - dists[mask]) / dists[mask] + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + forces[:, 0] += refinement_boundary_strength * np.maximum(0, boundary_margin - centers[:, 0]) + forces[:, 0] -= refinement_boundary_strength * np.maximum(0, centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += refinement_boundary_strength * np.maximum(0, boundary_margin - centers[:, 1]) + forces[:, 1] -= refinement_boundary_strength * np.maximum(0, centers[:, 1] - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") - VECTORIZED + annealing_iters = 1500 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + + for _ in range(annealing_iters): + diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + mask = (dists > 1e-9) & (dists < annealing_repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = annealing_repulsion_strength * (annealing_repulsion_threshold - dists[mask]) / dists[mask] + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + forces[:, 0] += annealing_boundary_strength * np.maximum(0, boundary_margin - centers[:, 0]) + forces[:, 0] -= annealing_boundary_strength * np.maximum(0, centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += annealing_boundary_strength * np.maximum(0, boundary_margin - centers[:, 1]) + forces[:, 1] -= annealing_boundary_strength * np.maximum(0, centers[:, 1] - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries using vectorized operation. + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations and tight tolerance ensures convergence. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/original.py new file mode 100644 index 0000000000000000000000000000000000000000..6ed16988b247ff6ace89d5bece766c7982a94bef --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/original.py @@ -0,0 +1,197 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Using (0.4, 0.2) breaks initial symmetry, encouraging unique, denser packings. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # Common boundary margin for all stages + boundary_margin = 0.04 + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # A new stage for final micro-adjustments with very weak forces and many iterations. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries using vectorized operation. + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations and tight tolerance ensures convergence. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..7362187cf3a6a36dfa1512da605f259b62d27344 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/job_log.err @@ -0,0 +1,15 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_113/main.py:70: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_113/main.py:92: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_113/main.py:114: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..c98786a3b6636e8f1afe2cd55589bcc37070f3bb --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_113/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_113/results +Run 1/1 completed in 0.41 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9606751500535253 + public: {'centers_str': ' centers[0] = (0.0819, 0.0970)\n centers[1] = (0.2691, 0.0570)\n centers[2] = (0.5299, 0.0567)\n centers[3] = (0.7127, 0.0972)\n centers[4] = (0.9067, 0.0969)\n centers[5] = (0.0810, 0.2996)\n centers[6] = (0.2667, 0.3319)\n centers[7] = (0.5322, 0.3321)\n centers[8] = (0.7135, 0.2994)\n centers[9] = (0.9068, 0.2995)\n centers[10] = (0.0962, 0.5006)\n centers[11] = (0.2996, 0.5130)\n centers[12] = (0.4999, 0.5130)\n centers[13] = (0.7010, 0.5006)\n centers[14] = (0.9033, 0.5000)\n centers[15] = (0.0969, 0.7007)\n centers[16] = (0.2995, 0.7038)\n centers[17] = (0.5000, 0.7038)\n centers[18] = (0.7005, 0.7007)\n centers[19] = (0.9031, 0.7005)\n centers[20] = (0.0969, 0.9031)\n centers[21] = (0.2995, 0.9037)\n centers[22] = (0.5000, 0.9037)\n centers[23] = (0.7005, 0.9031)\n centers[24] = (0.9031, 0.9031)\n centers[25] = (0.3999, 0.1986)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9606751500535253} + visualization_path: + execution_time_mean: 0.41006043180823326 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..411375ff715c0d6d34bed8cb32b940cd45f5088d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9606751500535253, + "public": { + "centers_str": " centers[0] = (0.0819, 0.0970)\n centers[1] = (0.2691, 0.0570)\n centers[2] = (0.5299, 0.0567)\n centers[3] = (0.7127, 0.0972)\n centers[4] = (0.9067, 0.0969)\n centers[5] = (0.0810, 0.2996)\n centers[6] = (0.2667, 0.3319)\n centers[7] = (0.5322, 0.3321)\n centers[8] = (0.7135, 0.2994)\n centers[9] = (0.9068, 0.2995)\n centers[10] = (0.0962, 0.5006)\n centers[11] = (0.2996, 0.5130)\n centers[12] = (0.4999, 0.5130)\n centers[13] = (0.7010, 0.5006)\n centers[14] = (0.9033, 0.5000)\n centers[15] = (0.0969, 0.7007)\n centers[16] = (0.2995, 0.7038)\n centers[17] = (0.5000, 0.7038)\n centers[18] = (0.7005, 0.7007)\n centers[19] = (0.9031, 0.7005)\n centers[20] = (0.0969, 0.9031)\n centers[21] = (0.2995, 0.9037)\n centers[22] = (0.5000, 0.9037)\n centers[23] = (0.7005, 0.9031)\n centers[24] = (0.9031, 0.9031)\n centers[25] = (0.3999, 0.1986)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9606751500535253 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_113/results/packing_viz.png", + "execution_time_mean": 0.41006043180823326, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..89314f9b67a8142c45693a4fe52dfba542b3e430 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_113/search_replace.txt @@ -0,0 +1,216 @@ +Based on my analysis of the visualization and the current code, the primary issue is the persistence of a grid-like structure. The relaxation process is not powerful enough to break free from this suboptimal local minimum. The use of slow, explicit Python loops for force calculations severely limits the number of iterations and the intensity of forces that can be applied within a reasonable time, causing the system to get "stuck". + +My strategy is twofold: +1. **Vectorize All The Things**: Replace the slow Python loops in both the initial grid deformation and all three relaxation stages with highly efficient, vectorized NumPy operations. This is a fundamental performance enhancement that reintroduces a key feature from previous successful programs. +2. **Amplify and Extend Relaxation**: Leverage the massive speedup from vectorization to make the relaxation process more aggressive and thorough. I will increase the number of iterations in all stages and strengthen the forces in the initial "shaking" phase to properly shatter the grid structure, allowing the circles to find a more globally optimal, dense configuration. + +I will propose two distinct changes to implement this strategy. + + +vectorize_gaussian_push + + +The initial placement of circles involves deforming a 5x5 grid by pushing points away from a `void_center`. The original code used a Python loop for this, which is inefficient. I am replacing this with a fully vectorized NumPy implementation. This calculates all displacements and push magnitudes simultaneously, which is significantly faster. I'm also increasing the `amplitude` from 0.06 to 0.08 to create a more aggressive initial deformation, which should help break the grid symmetry more effectively and prevent the system from getting stuck in the obvious grid-like local minimum seen in the visualization. + + +<<<<<<< SEARCH + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement +======= + # Increased amplitude to create a larger initial void. + amplitude = 0.08 + sigma = 0.15 + + # Vectorized Gaussian push for efficiency and clarity + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + # Normalize displacement vectors + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +>>>>>>> REPLACE + + +vectorize_and_strengthen_relaxation + + +The core issue with the current program is its slow, loop-based force calculation, which prevents the packing from escaping the grid-like structure seen in the visualization. I am replacing all three relaxation stages (Exploration, Refinement, Annealing) with a single, highly efficient, vectorized NumPy implementation. + +This massive performance gain is used to make the simulation more effective: +1. **Exploration**: Iterations are increased (300->800) and forces strengthened (`strength` 0.025->0.03, `boundary` 0.1->0.15, `threshold` 0.2->0.21) to shatter the grid. +2. **Refinement**: Iterations are doubled (500->1000) for a better settling period. +3. **Annealing**: Iterations are nearly doubled (800->1500) for fine-grained polishing. + +This change directly addresses the observed stagnation by enabling a more powerful and extended search for a denser configuration. + + +<<<<<<< SEARCH + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # A new stage for final micro-adjustments with very weak forces and many iterations. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) +======= + # 4. Stage 1: High-Energy Exploration ("Shaking") - VECTORIZED + # Now vectorized, we can use more iterations and stronger forces to shatter the grid. + exploration_iters = 800 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.03 + exploration_boundary_strength = 0.15 + exploration_repulsion_threshold = 0.21 + + for _ in range(exploration_iters): + diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + mask = (dists > 1e-9) & (dists < exploration_repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = exploration_repulsion_strength * (exploration_repulsion_threshold - dists[mask]) / dists[mask] + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + forces[:, 0] += exploration_boundary_strength * np.maximum(0, boundary_margin - centers[:, 0]) + forces[:, 0] -= exploration_boundary_strength * np.maximum(0, centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += exploration_boundary_strength * np.maximum(0, boundary_margin - centers[:, 1]) + forces[:, 1] -= exploration_boundary_strength * np.maximum(0, centers[:, 1] - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") - VECTORIZED + refinement_iters = 1000 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.05 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + mask = (dists > 1e-9) & (dists < refinement_repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = refinement_repulsion_strength * (refinement_repulsion_threshold - dists[mask]) / dists[mask] + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + forces[:, 0] += refinement_boundary_strength * np.maximum(0, boundary_margin - centers[:, 0]) + forces[:, 0] -= refinement_boundary_strength * np.maximum(0, centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += refinement_boundary_strength * np.maximum(0, boundary_margin - centers[:, 1]) + forces[:, 1] -= refinement_boundary_strength * np.maximum(0, centers[:, 1] - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") - VECTORIZED + annealing_iters = 1500 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + + for _ in range(annealing_iters): + diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + mask = (dists > 1e-9) & (dists < annealing_repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = annealing_repulsion_strength * (annealing_repulsion_threshold - dists[mask]) / dists[mask] + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + forces[:, 0] += annealing_boundary_strength * np.maximum(0, boundary_margin - centers[:, 0]) + forces[:, 0] -= annealing_boundary_strength * np.maximum(0, centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += annealing_boundary_strength * np.maximum(0, boundary_margin - centers[:, 1]) + forces[:, 1] -= annealing_boundary_strength * np.maximum(0, centers[:, 1] - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d0aa3c54fcd67a2b7e6ef44a4088219ed99cfbca Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..0a97f86f68eeeae1e5e3d9b8a94440d22bec836c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_114/main.py:84: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..47513705d7206f24d9fd369ed165a013c8cba1c1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_114/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_114/results +Run 1/1 completed in 0.19 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.672629642935905 + public: {'centers_str': ' centers[0] = (0.1066, 0.1066)\n centers[1] = (0.2998, 0.1198)\n centers[2] = (0.4811, 0.1327)\n centers[3] = (0.6558, 0.1095)\n centers[4] = (0.8706, 0.0800)\n centers[5] = (0.1198, 0.2998)\n centers[6] = (0.3269, 0.3269)\n centers[7] = (0.5263, 0.3589)\n centers[8] = (0.7048, 0.2926)\n centers[9] = (0.8941, 0.2553)\n centers[10] = (0.1327, 0.4811)\n centers[11] = (0.3589, 0.5263)\n centers[12] = (0.5532, 0.5532)\n centers[13] = (0.7534, 0.5102)\n centers[14] = (0.9224, 0.4768)\n centers[15] = (0.1095, 0.6558)\n centers[16] = (0.2926, 0.7048)\n centers[17] = (0.5102, 0.7534)\n centers[18] = (0.7227, 0.7227)\n centers[19] = (0.9132, 0.6987)\n centers[20] = (0.0800, 0.8706)\n centers[21] = (0.2553, 0.8941)\n centers[22] = (0.4768, 0.9224)\n centers[23] = (0.6987, 0.9132)\n centers[24] = (0.9011, 0.9011)\n centers[25] = (0.5532, 0.5532)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.672629642935905} + visualization_path: + execution_time_mean: 0.19168365886434913 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..992e6c14ddfac8ffb391fab7d5fe4b5acb13eeb4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.672629642935905, + "public": { + "centers_str": " centers[0] = (0.1066, 0.1066)\n centers[1] = (0.2998, 0.1198)\n centers[2] = (0.4811, 0.1327)\n centers[3] = (0.6558, 0.1095)\n centers[4] = (0.8706, 0.0800)\n centers[5] = (0.1198, 0.2998)\n centers[6] = (0.3269, 0.3269)\n centers[7] = (0.5263, 0.3589)\n centers[8] = (0.7048, 0.2926)\n centers[9] = (0.8941, 0.2553)\n centers[10] = (0.1327, 0.4811)\n centers[11] = (0.3589, 0.5263)\n centers[12] = (0.5532, 0.5532)\n centers[13] = (0.7534, 0.5102)\n centers[14] = (0.9224, 0.4768)\n centers[15] = (0.1095, 0.6558)\n centers[16] = (0.2926, 0.7048)\n centers[17] = (0.5102, 0.7534)\n centers[18] = (0.7227, 0.7227)\n centers[19] = (0.9132, 0.6987)\n centers[20] = (0.0800, 0.8706)\n centers[21] = (0.2553, 0.8941)\n centers[22] = (0.4768, 0.9224)\n centers[23] = (0.6987, 0.9132)\n centers[24] = (0.9011, 0.9011)\n centers[25] = (0.5532, 0.5532)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.672629642935905 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_114/results/packing_viz.png", + "execution_time_mean": 0.19168365886434913, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..26314b8399318a3b076b57a1a0321c4ffbf75c6e Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..6c81fe19e4ba49b86762a825344863ee61eaef54 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_115/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_115/results +Run 1/1 completed in 0.24 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9477886238575808 + public: {'centers_str': ' centers[0] = (0.0739, 0.0739)\n centers[1] = (0.3244, 0.0623)\n centers[2] = (0.5085, 0.0968)\n centers[3] = (0.7007, 0.1001)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0628, 0.3237)\n centers[6] = (0.3375, 0.3379)\n centers[7] = (0.5113, 0.3030)\n centers[8] = (0.7010, 0.3003)\n centers[9] = (0.9000, 0.3000)\n centers[10] = (0.0965, 0.5086)\n centers[11] = (0.3021, 0.5111)\n centers[12] = (0.5015, 0.5015)\n centers[13] = (0.7001, 0.5001)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.0997, 0.7008)\n centers[16] = (0.2998, 0.7009)\n centers[17] = (0.5000, 0.7001)\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.2191, 0.2178)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9477886238575808} + visualization_path: + execution_time_mean: 0.24027182208374143 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..97aa996e01ebd5476daaa7f211ccc48f0ae371fc --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9477886238575808, + "public": { + "centers_str": " centers[0] = (0.0739, 0.0739)\n centers[1] = (0.3244, 0.0623)\n centers[2] = (0.5085, 0.0968)\n centers[3] = (0.7007, 0.1001)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0628, 0.3237)\n centers[6] = (0.3375, 0.3379)\n centers[7] = (0.5113, 0.3030)\n centers[8] = (0.7010, 0.3003)\n centers[9] = (0.9000, 0.3000)\n centers[10] = (0.0965, 0.5086)\n centers[11] = (0.3021, 0.5111)\n centers[12] = (0.5015, 0.5015)\n centers[13] = (0.7001, 0.5001)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.0997, 0.7008)\n centers[16] = (0.2998, 0.7009)\n centers[17] = (0.5000, 0.7001)\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.2191, 0.2178)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9477886238575808 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_115/results/packing_viz.png", + "execution_time_mean": 0.24027182208374143, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8782fb75b99d624a9c02ca7f53e3177092589f5 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..7d97ad85a6348a238870547c638262d47baa5af6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_116/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_116/results +Run 1/1 completed in 16.82 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.2005850583514306 + public: {'centers_str': ' centers[0] = (0.0932, 0.0933)\n centers[1] = (0.2425, 0.0598)\n centers[2] = (0.5472, 0.0959)\n centers[3] = (0.7140, 0.0724)\n centers[4] = (0.8878, 0.1039)\n centers[5] = (0.0791, 0.2649)\n centers[6] = (0.3565, 0.5959)\n centers[7] = (0.5455, 0.3688)\n centers[8] = (0.7056, 0.2441)\n centers[9] = (0.9006, 0.3071)\n centers[10] = (0.1041, 0.4466)\n centers[11] = (0.2500, 0.5400)\n centers[12] = (0.4892, 0.5778)\n centers[13] = (0.6926, 0.5018)\n centers[14] = (0.9069, 0.5026)\n centers[15] = (0.1093, 0.6673)\n centers[16] = (0.3194, 0.6971)\n centers[17] = (0.5204, 0.7203)\n centers[18] = (0.7038, 0.6972)\n centers[19] = (0.9034, 0.7043)\n centers[20] = (0.1024, 0.8814)\n centers[21] = (0.3024, 0.9014)\n centers[22] = (0.5005, 0.9005)\n centers[23] = (0.7000, 0.9000)\n centers[24] = (0.8995, 0.9004)\n centers[25] = (0.3807, 0.2255)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.2005850583514306} + visualization_path: + execution_time_mean: 16.816528293304145 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..dc0153515a94aada69f2e1fcf24c41c2eb43c6cb --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.2005850583514306, + "public": { + "centers_str": " centers[0] = (0.0932, 0.0933)\n centers[1] = (0.2425, 0.0598)\n centers[2] = (0.5472, 0.0959)\n centers[3] = (0.7140, 0.0724)\n centers[4] = (0.8878, 0.1039)\n centers[5] = (0.0791, 0.2649)\n centers[6] = (0.3565, 0.5959)\n centers[7] = (0.5455, 0.3688)\n centers[8] = (0.7056, 0.2441)\n centers[9] = (0.9006, 0.3071)\n centers[10] = (0.1041, 0.4466)\n centers[11] = (0.2500, 0.5400)\n centers[12] = (0.4892, 0.5778)\n centers[13] = (0.6926, 0.5018)\n centers[14] = (0.9069, 0.5026)\n centers[15] = (0.1093, 0.6673)\n centers[16] = (0.3194, 0.6971)\n centers[17] = (0.5204, 0.7203)\n centers[18] = (0.7038, 0.6972)\n centers[19] = (0.9034, 0.7043)\n centers[20] = (0.1024, 0.8814)\n centers[21] = (0.3024, 0.9014)\n centers[22] = (0.5005, 0.9005)\n centers[23] = (0.7000, 0.9000)\n centers[24] = (0.8995, 0.9004)\n centers[25] = (0.3807, 0.2255)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.2005850583514306 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_116/results/packing_viz.png", + "execution_time_mean": 16.816528293304145, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f7ce57b0055a1fbbbf5f5067c86f09f24c47351 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..81c3e9b46556f9f0e87380c544714439ad2a8a6f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/edit.diff @@ -0,0 +1,290 @@ +--- a/original.py ++++ b/original.py +@@ -1,208 +1,239 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ +- Construct a specific arrangement of 26 circles in a unit square +- that attempts to maximize the sum of their radii. +- +- This method starts with a 5x5 grid, deforms it by creating an asymmetric void +- using a Gaussian repulsive force, and then uses a three-stage force-directed +- relaxation (Exploration, Refinement, Annealing) to settle the circles into +- a dense packing. ++ Constructs a high-density arrangement of 26 circles by combining a ++ Gaussian-deformed and perturbed grid initialization with a three-stage ++ adaptive force-directed relaxation, incorporating decaying step sizes ++ and a two-tier repulsion force. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + +- # 1. Start with a 5x5 grid, the basis for N=25 packing. ++ # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Define an asymmetric interstitial void center to break symmetry. +- # This position is taken from the best-performing parent program. ++ # Add a small random perturbation to break initial grid symmetry more effectively. ++ # This helps escape local minima that resemble the initial grid. ++ perturbation_scale = 0.007 ++ base_centers_25 += np.random.normal(0, perturbation_scale, size=base_centers_25.shape) ++ ++ # 2. Place the 26th circle in an asymmetric void and deform the grid. + void_center = np.array([0.4, 0.2]) +- +- # 3. Deform the grid using a vectorized Gaussian push. +- # The amplitude is increased to match high-performing parents, to better break the initial grid. +- amplitude = 0.06 # Magnitude of the push. +- sigma = 0.15 # Spatial extent of the push. +- ++ amplitude = 0.06 # Magnitude of the push ++ sigma = 0.15 # Spatial extent of the push ++ ++ # Vectorized calculation for Gaussian displacement + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + +- # Normalize displacement vectors and apply the push + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th and clip to bounds. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + +- # 4. Three-Stage Adaptive Force-Directed Relaxation (Aggressive Shake, Settle, Polish) +- # The parameters are heavily based on a successful parent program to break out of the +- # grid-like local minimum observed in the visualization. ++ # 3. Three-Stage Adaptive Force-Directed Relaxation ++ # Each stage features adaptive step sizes (decaying over iterations) and a two-tier ++ # repulsion force profile (stronger when circles are very close). + + # Stage 1: High-Energy Exploration ("Shaking") +- exploration_iters = 300 +- exploration_step_size = 0.003 +- exploration_repulsion_strength = 0.025 +- exploration_repulsion_threshold = 0.20 +- exploration_boundary_strength = 0.1 +- exploration_boundary_margin = 0.05 # Progressively smaller margins +- +- for _ in range(exploration_iters): ++ exploration_iters = 350 ++ exploration_initial_step_size = 0.004 ++ exploration_step_decay_factor = 0.998 # Decays step size within this stage ++ exploration_repulsion_strength = 0.03 ++ exploration_boundary_strength = 0.12 ++ exploration_repulsion_threshold = 0.21 ++ exploration_boundary_margin = 0.05 ++ exploration_strong_repulsion_factor = 2.5 # Factor for extremely close circles ++ exploration_strong_repulsion_distance_ratio = 0.2 # Below this ratio, strong repulsion applies ++ ++ for k in range(exploration_iters): ++ current_step_size = exploration_initial_step_size * (exploration_step_decay_factor ** k) + forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist ++ # Apply two-tier repulsion: stronger for very close circles ++ if dist < exploration_repulsion_threshold * exploration_strong_repulsion_distance_ratio: ++ force_magnitude *= exploration_strong_repulsion_factor + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec ++ ++ # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) +- centers += exploration_step_size * forces ++ ++ centers += current_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement ("Settling") +- refinement_iters = 500 +- refinement_step_size = 0.0005 +- refinement_repulsion_strength = 0.01 +- refinement_repulsion_threshold = 0.185 +- refinement_boundary_strength = 0.04 +- refinement_boundary_margin = 0.03 # Smaller margin for tighter boundary fit +- +- for _ in range(refinement_iters): ++ refinement_iters = 700 ++ refinement_initial_step_size = 0.001 ++ refinement_step_decay_factor = 0.999 ++ refinement_repulsion_strength = 0.015 ++ refinement_boundary_strength = 0.06 ++ refinement_repulsion_threshold = 0.19 ++ refinement_boundary_margin = 0.03 ++ refinement_strong_repulsion_factor = 2.0 ++ refinement_strong_repulsion_distance_ratio = 0.15 ++ ++ for k in range(refinement_iters): ++ current_step_size = refinement_initial_step_size * (refinement_step_decay_factor ** k) + forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist ++ if dist < refinement_repulsion_threshold * refinement_strong_repulsion_distance_ratio: ++ force_magnitude *= refinement_strong_repulsion_factor + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec ++ ++ # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) +- centers += refinement_step_size * forces ++ ++ centers += current_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Ultra-Low-Energy Annealing ("Polishing") +- annealing_iters = 800 +- annealing_step_size = 0.0001 +- annealing_repulsion_strength = 0.004 ++ annealing_iters = 1500 # Significantly increased iterations for fine-tuning ++ annealing_initial_step_size = 0.0003 ++ annealing_step_decay_factor = 0.9995 ++ annealing_repulsion_strength = 0.005 ++ annealing_boundary_strength = 0.03 + annealing_repulsion_threshold = 0.18 +- annealing_boundary_strength = 0.02 +- annealing_boundary_margin = 0.01 # Minimal margin for ultimate boundary contact +- +- for _ in range(annealing_iters): ++ annealing_boundary_margin = 0.005 # Smallest margin to hug the edges ++ annealing_strong_repulsion_factor = 1.5 ++ annealing_strong_repulsion_distance_ratio = 0.1 ++ ++ for k in range(annealing_iters): ++ current_step_size = annealing_initial_step_size * (annealing_step_decay_factor ** k) + forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist ++ if dist < annealing_repulsion_threshold * annealing_strong_repulsion_distance_ratio: ++ force_magnitude *= annealing_strong_repulsion_factor + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec ++ ++ # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) +- centers += annealing_step_size * forces ++ ++ centers += current_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + +- # 5. Compute maximum valid radii for the final configuration. ++ # 4. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). +- # This is more efficient than a loop. + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # Increased iterations for robust convergence. + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change before updating + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/main.py new file mode 100644 index 0000000000000000000000000000000000000000..fdf1301a8663f2e6403562a5fb969113af5656f5 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/main.py @@ -0,0 +1,239 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by combining a + Gaussian-deformed and perturbed grid initialization with a three-stage + adaptive force-directed relaxation, incorporating decaying step sizes + and a two-tier repulsion force. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Add a small random perturbation to break initial grid symmetry more effectively. + # This helps escape local minima that resemble the initial grid. + perturbation_scale = 0.007 + base_centers_25 += np.random.normal(0, perturbation_scale, size=base_centers_25.shape) + + # 2. Place the 26th circle in an asymmetric void and deform the grid. + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 # Magnitude of the push + sigma = 0.15 # Spatial extent of the push + + # Vectorized calculation for Gaussian displacement + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th and clip to bounds. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 3. Three-Stage Adaptive Force-Directed Relaxation + # Each stage features adaptive step sizes (decaying over iterations) and a two-tier + # repulsion force profile (stronger when circles are very close). + + # Stage 1: High-Energy Exploration ("Shaking") + exploration_iters = 350 + exploration_initial_step_size = 0.004 + exploration_step_decay_factor = 0.998 # Decays step size within this stage + exploration_repulsion_strength = 0.03 + exploration_boundary_strength = 0.12 + exploration_repulsion_threshold = 0.21 + exploration_boundary_margin = 0.05 + exploration_strong_repulsion_factor = 2.5 # Factor for extremely close circles + exploration_strong_repulsion_distance_ratio = 0.2 # Below this ratio, strong repulsion applies + + for k in range(exploration_iters): + current_step_size = exploration_initial_step_size * (exploration_step_decay_factor ** k) + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + # Apply two-tier repulsion: stronger for very close circles + if dist < exploration_repulsion_threshold * exploration_strong_repulsion_distance_ratio: + force_magnitude *= exploration_strong_repulsion_factor + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + + centers += current_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement ("Settling") + refinement_iters = 700 + refinement_initial_step_size = 0.001 + refinement_step_decay_factor = 0.999 + refinement_repulsion_strength = 0.015 + refinement_boundary_strength = 0.06 + refinement_repulsion_threshold = 0.19 + refinement_boundary_margin = 0.03 + refinement_strong_repulsion_factor = 2.0 + refinement_strong_repulsion_distance_ratio = 0.15 + + for k in range(refinement_iters): + current_step_size = refinement_initial_step_size * (refinement_step_decay_factor ** k) + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + if dist < refinement_repulsion_threshold * refinement_strong_repulsion_distance_ratio: + force_magnitude *= refinement_strong_repulsion_factor + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + centers += current_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Ultra-Low-Energy Annealing ("Polishing") + annealing_iters = 1500 # Significantly increased iterations for fine-tuning + annealing_initial_step_size = 0.0003 + annealing_step_decay_factor = 0.9995 + annealing_repulsion_strength = 0.005 + annealing_boundary_strength = 0.03 + annealing_repulsion_threshold = 0.18 + annealing_boundary_margin = 0.005 # Smallest margin to hug the edges + annealing_strong_repulsion_factor = 1.5 + annealing_strong_repulsion_distance_ratio = 0.1 + + for k in range(annealing_iters): + current_step_size = annealing_initial_step_size * (annealing_step_decay_factor ** k) + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + if dist < annealing_repulsion_threshold * annealing_strong_repulsion_distance_ratio: + force_magnitude *= annealing_strong_repulsion_factor + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + + centers += current_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 4. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # Increased iterations for robust convergence. + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change before updating + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/original.py new file mode 100644 index 0000000000000000000000000000000000000000..4e0b7815ae708b6bc1f5d71e131c61ccc984a945 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/original.py @@ -0,0 +1,208 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid, deforms it by creating an asymmetric void + using a Gaussian repulsive force, and then uses a three-stage force-directed + relaxation (Exploration, Refinement, Annealing) to settle the circles into + a dense packing. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an asymmetric interstitial void center to break symmetry. + # This position is taken from the best-performing parent program. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the grid using a vectorized Gaussian push. + # The amplitude is increased to match high-performing parents, to better break the initial grid. + amplitude = 0.06 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th and clip to bounds. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Three-Stage Adaptive Force-Directed Relaxation (Aggressive Shake, Settle, Polish) + # The parameters are heavily based on a successful parent program to break out of the + # grid-like local minimum observed in the visualization. + + # Stage 1: High-Energy Exploration ("Shaking") + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_repulsion_threshold = 0.20 + exploration_boundary_strength = 0.1 + exploration_boundary_margin = 0.05 # Progressively smaller margins + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement ("Settling") + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_repulsion_threshold = 0.185 + refinement_boundary_strength = 0.04 + refinement_boundary_margin = 0.03 # Smaller margin for tighter boundary fit + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Ultra-Low-Energy Annealing ("Polishing") + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_repulsion_threshold = 0.18 + annealing_boundary_strength = 0.02 + annealing_boundary_margin = 0.01 # Minimal margin for ultimate boundary contact + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + # This is more efficient than a loop. + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # Increased iterations for robust convergence. + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change before updating + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..1fdbab56c9a5cbd6169cba59560e49a9903dd1e9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_117/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_117/results +Run 1/1 completed in 2.68 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9421101927077462 + public: {'centers_str': ' centers[0] = (0.0938, 0.0931)\n centers[1] = (0.2869, 0.0622)\n centers[2] = (0.5188, 0.0617)\n centers[3] = (0.6979, 0.0899)\n centers[4] = (0.8990, 0.1040)\n centers[5] = (0.0860, 0.2986)\n centers[6] = (0.2729, 0.3258)\n centers[7] = (0.5295, 0.3332)\n centers[8] = (0.7178, 0.2980)\n centers[9] = (0.9167, 0.2977)\n centers[10] = (0.0853, 0.4969)\n centers[11] = (0.2958, 0.5097)\n centers[12] = (0.5042, 0.5089)\n centers[13] = (0.6977, 0.4994)\n centers[14] = (0.9012, 0.5050)\n centers[15] = (0.0952, 0.6991)\n centers[16] = (0.3020, 0.7032)\n centers[17] = (0.4956, 0.7018)\n centers[18] = (0.6895, 0.7072)\n centers[19] = (0.8895, 0.7046)\n centers[20] = (0.0938, 0.8989)\n centers[21] = (0.3122, 0.8988)\n centers[22] = (0.5006, 0.9073)\n centers[23] = (0.6938, 0.9080)\n centers[24] = (0.8990, 0.9048)\n centers[25] = (0.4018, 0.2013)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9421101927077462} + visualization_path: + execution_time_mean: 2.6839159349910915 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..c76202f901e25ebac480d94f2e3a1b8bf26dc924 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9421101927077462, + "public": { + "centers_str": " centers[0] = (0.0938, 0.0931)\n centers[1] = (0.2869, 0.0622)\n centers[2] = (0.5188, 0.0617)\n centers[3] = (0.6979, 0.0899)\n centers[4] = (0.8990, 0.1040)\n centers[5] = (0.0860, 0.2986)\n centers[6] = (0.2729, 0.3258)\n centers[7] = (0.5295, 0.3332)\n centers[8] = (0.7178, 0.2980)\n centers[9] = (0.9167, 0.2977)\n centers[10] = (0.0853, 0.4969)\n centers[11] = (0.2958, 0.5097)\n centers[12] = (0.5042, 0.5089)\n centers[13] = (0.6977, 0.4994)\n centers[14] = (0.9012, 0.5050)\n centers[15] = (0.0952, 0.6991)\n centers[16] = (0.3020, 0.7032)\n centers[17] = (0.4956, 0.7018)\n centers[18] = (0.6895, 0.7072)\n centers[19] = (0.8895, 0.7046)\n centers[20] = (0.0938, 0.8989)\n centers[21] = (0.3122, 0.8988)\n centers[22] = (0.5006, 0.9073)\n centers[23] = (0.6938, 0.9080)\n centers[24] = (0.8990, 0.9048)\n centers[25] = (0.4018, 0.2013)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9421101927077462 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_117/results/packing_viz.png", + "execution_time_mean": 2.6839159349910915, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..01c24d729b2a33f233be2251e92cacd2de1f538c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_117/rewrite.txt @@ -0,0 +1,230 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by combining a + Gaussian-deformed and perturbed grid initialization with a three-stage + adaptive force-directed relaxation, incorporating decaying step sizes + and a two-tier repulsion force. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Add a small random perturbation to break initial grid symmetry more effectively. + # This helps escape local minima that resemble the initial grid. + perturbation_scale = 0.007 + base_centers_25 += np.random.normal(0, perturbation_scale, size=base_centers_25.shape) + + # 2. Place the 26th circle in an asymmetric void and deform the grid. + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 # Magnitude of the push + sigma = 0.15 # Spatial extent of the push + + # Vectorized calculation for Gaussian displacement + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th and clip to bounds. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 3. Three-Stage Adaptive Force-Directed Relaxation + # Each stage features adaptive step sizes (decaying over iterations) and a two-tier + # repulsion force profile (stronger when circles are very close). + + # Stage 1: High-Energy Exploration ("Shaking") + exploration_iters = 350 + exploration_initial_step_size = 0.004 + exploration_step_decay_factor = 0.998 # Decays step size within this stage + exploration_repulsion_strength = 0.03 + exploration_boundary_strength = 0.12 + exploration_repulsion_threshold = 0.21 + exploration_boundary_margin = 0.05 + exploration_strong_repulsion_factor = 2.5 # Factor for extremely close circles + exploration_strong_repulsion_distance_ratio = 0.2 # Below this ratio, strong repulsion applies + + for k in range(exploration_iters): + current_step_size = exploration_initial_step_size * (exploration_step_decay_factor ** k) + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + # Apply two-tier repulsion: stronger for very close circles + if dist < exploration_repulsion_threshold * exploration_strong_repulsion_distance_ratio: + force_magnitude *= exploration_strong_repulsion_factor + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + + centers += current_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement ("Settling") + refinement_iters = 700 + refinement_initial_step_size = 0.001 + refinement_step_decay_factor = 0.999 + refinement_repulsion_strength = 0.015 + refinement_boundary_strength = 0.06 + refinement_repulsion_threshold = 0.19 + refinement_boundary_margin = 0.03 + refinement_strong_repulsion_factor = 2.0 + refinement_strong_repulsion_distance_ratio = 0.15 + + for k in range(refinement_iters): + current_step_size = refinement_initial_step_size * (refinement_step_decay_factor ** k) + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + if dist < refinement_repulsion_threshold * refinement_strong_repulsion_distance_ratio: + force_magnitude *= refinement_strong_repulsion_factor + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + centers += current_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Ultra-Low-Energy Annealing ("Polishing") + annealing_iters = 1500 # Significantly increased iterations for fine-tuning + annealing_initial_step_size = 0.0003 + annealing_step_decay_factor = 0.9995 + annealing_repulsion_strength = 0.005 + annealing_boundary_strength = 0.03 + annealing_repulsion_threshold = 0.18 + annealing_boundary_margin = 0.005 # Smallest margin to hug the edges + annealing_strong_repulsion_factor = 1.5 + annealing_strong_repulsion_distance_ratio = 0.1 + + for k in range(annealing_iters): + current_step_size = annealing_initial_step_size * (annealing_step_decay_factor ** k) + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + if dist < annealing_repulsion_threshold * annealing_strong_repulsion_distance_ratio: + force_magnitude *= annealing_strong_repulsion_factor + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + + centers += current_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 4. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # Increased iterations for robust convergence. + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change before updating + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a016097267acbfe41463399d6d184ca3f4acc76e Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..eadd2455a6fb7210b95513be0035dd3e6ee8d1aa --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/edit.diff @@ -0,0 +1,276 @@ +--- a/original.py ++++ b/original.py +@@ -1,176 +1,153 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles using vectorized relaxation.""" ++"""Constructor-based circle packing for n=26 circles""" + + import numpy as np + ++# This function remains largely the same as it is a robust way to evaluate a given center configuration. ++def compute_max_radii(centers): ++ """ ++ Compute the maximum possible radii for each circle position ++ such that they don't overlap and stay within the unit square. This is ++ an iterative version that converges to a stable solution. + +-def _relax_stage_vectorized(centers, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): +- """ +- Perform a single stage of force-directed relaxation using vectorized calculations. ++ Args: ++ centers: np.array of shape (n, 2) with (x, y) coordinates ++ ++ Returns: ++ np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] +- for _ in range(iters): +- # 1. Circle-circle repulsion forces (vectorized) +- # Compute all pairwise differences and distances +- diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] +- dists = np.linalg.norm(diff, axis=-1) + +- # Create a mask for pairs that are close enough to repel, excluding self-pairs +- mask = (dists > 1e-9) & (dists < repulsion_threshold) +- +- # Calculate force magnitudes for the masked pairs +- force_magnitudes = np.zeros_like(dists) +- force_magnitudes[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] +- +- # Normalize the difference vectors to get force directions +- force_directions = np.zeros_like(diff) +- # Add a small epsilon to dists in the denominator to avoid division by zero +- force_directions[mask] = diff[mask] / (dists[mask, np.newaxis] + 1e-12) ++ # Initialize radii based on distance to the square's boundaries (vectorized). ++ radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + +- # Calculate the total force vector for each circle +- forces = np.sum(force_directions * force_magnitudes[:, :, np.newaxis], axis=1) ++ # Iteratively resolve overlaps between circles until no more changes occur. ++ # A high number of iterations ensures convergence for complex arrangements. ++ for _ in range(500): # Increased iterations for more thorough convergence ++ changes_made = False ++ for i in range(n): ++ for j in range(i + 1, n): ++ dist = np.linalg.norm(centers[i] - centers[j]) + +- # 2. Boundary repulsion forces +- # Left boundary +- is_left = centers[:, 0] < boundary_margin +- forces[is_left, 0] += boundary_strength * (boundary_margin - centers[is_left, 0]) +- # Right boundary +- is_right = centers[:, 0] > 1 - boundary_margin +- forces[is_right, 0] -= boundary_strength * (centers[is_right, 0] - (1 - boundary_margin)) +- # Bottom boundary +- is_bottom = centers[:, 1] < boundary_margin +- forces[is_bottom, 1] += boundary_strength * (boundary_margin - centers[is_bottom, 1]) +- # Top boundary +- is_top = centers[:, 1] > 1 - boundary_margin +- forces[is_top, 1] -= boundary_strength * (centers[is_top, 1] - (1 - boundary_margin)) ++ # If they overlap (with a small tolerance for floating point math) ++ if radii[i] + radii[j] > dist + 1e-12: ++ sum_r = radii[i] + radii[j] ++ if sum_r > 1e-12: # Avoid division by zero ++ # Scale both radii down proportionally to resolve the overlap. ++ # This ensures the ratio of radii is maintained if possible ++ # while eliminating overlap. ++ scale = dist / sum_r ++ ri_new, rj_new = radii[i] * scale, radii[j] * scale ++ ++ # Check for significant change to set the flag ++ if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: ++ radii[i], radii[j] = ri_new, rj_new ++ changes_made = True ++ else: # If both radii are already ~0, ensure they are exactly 0 ++ radii[i] = 0 ++ radii[j] = 0 + +- # 3. Update positions and clip +- centers += step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- +- return centers ++ changes_made = True + ++ # If a full pass resulted in no changes, the packing is stable. ++ if not changes_made: ++ break ++ ++ return radii + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles using an asymmetric +- void initialization and a three-stage vectorized force-directed relaxation. ++ Constructs a high-density arrangement of 26 circles using an iterative ++ local search algorithm with targeted perturbations and greedy acceptance, ++ starting from an asymmetric Gaussian-deformed grid. This combines the ++ successful local search strategy with a robust radii computation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 +- +- # 1. Start with a 5x5 grid for the first 25 circles. ++ ++ # 1. Initial Grid Generation (from the high-scoring prior program) + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Use an ASYMMETRIC void center, a critical feature of high-scoring solutions. ++ # Asymmetric void to break symmetry and provide a starting point for rearrangement + void_center = np.array([0.4, 0.2]) ++ amplitude = 0.06 # Amplitude from the high-scoring prior ++ sigma = 0.15 + +- # 3. Deform the grid with a Gaussian push to create space for the 26th circle. +- # A slightly increased amplitude creates a better initial void. +- amplitude = 0.065 +- sigma = 0.15 +- + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + +- deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- +- centers = np.zeros((n, 2)) +- centers[:25] = deformed_centers_25 +- centers[25] = void_center +- centers = np.clip(centers, 0.0, 1.0) +- +- # === STAGE 1: High-Energy Exploration (Vectorized) === +- # Aggressive parameters to break the grid structure quickly. +- centers = _relax_stage_vectorized( +- centers, +- iters=400, +- step_size=0.003, +- repulsion_strength=0.03, +- boundary_strength=0.1, +- repulsion_threshold=0.20, +- boundary_margin=0.05 +- ) ++ initial_centers = np.zeros((n, 2)) ++ initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ initial_centers[25] = void_center ++ initial_centers = np.clip(initial_centers, 0.0, 1.0) + +- # === STAGE 2: Refinement (Vectorized) === +- # Reduced forces to settle the circles into a good configuration. +- centers = _relax_stage_vectorized( +- centers, +- iters=600, +- step_size=0.0005, +- repulsion_strength=0.01, +- boundary_strength=0.05, +- repulsion_threshold=0.185, +- boundary_margin=0.03 +- ) ++ # 2. Iterative Local Search Optimization (from the high-scoring prior program) ++ best_centers = initial_centers.copy() ++ best_radii = compute_max_radii(best_centers) ++ best_sum_radii = np.sum(best_radii) ++ ++ # Main parameters for the local search ++ total_iterations = 8000 # High number of iterations for thorough search ++ initial_perturb_strength = 0.02 # Initial maximum perturbation for exploration ++ final_perturb_strength = 0.0005 # Final minimum perturbation for fine-tuning ++ ++ for iteration in range(total_iterations): ++ # Linearly decay perturbation strength over iterations ++ perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) ++ ++ candidate_centers = best_centers.copy() ++ ++ # Target circles that are currently small (more likely to be stuck). ++ # This biases the search towards improving less optimized parts of the packing. ++ # Calculate inverse radii, normalize to get probabilities. ++ # Add a small constant to avoid division by zero for radius 0. ++ inverse_radii = 1 / (best_radii + 1e-8) # Using best_radii from previous best state ++ selection_probs = inverse_radii / np.sum(inverse_radii) + +- # === STAGE 3: Annealing (Vectorized) === +- # Very weak forces and many iterations for final micro-adjustments. +- centers = _relax_stage_vectorized( +- centers, +- iters=1200, +- step_size=0.0001, +- repulsion_strength=0.005, +- boundary_strength=0.03, +- repulsion_threshold=0.180, +- boundary_margin=0.005 +- ) ++ # Select a circle to perturb based on its probability ++ circle_idx = np.random.choice(n, p=selection_probs) + +- # 4. Compute final radii for the optimized configuration. +- radii = compute_max_radii(centers) +- return centers, radii ++ # Generate a random displacement for the selected circle ++ displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) ++ candidate_centers[circle_idx] += displacement + ++ # Clip the candidate center to remain within the unit square ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + +-def compute_max_radii(centers): +- """ +- Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This is +- an iterative version that converges to a stable solution. +- """ +- n = centers.shape[0] ++ # Evaluate the new configuration ++ candidate_radii = compute_max_radii(candidate_centers) ++ candidate_sum_radii = np.sum(candidate_radii) + +- # Initialize radii based on distance to the square's boundaries (vectorized). +- radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) ++ # Greedy acceptance: if the new configuration is better, accept it ++ if candidate_sum_radii > best_sum_radii: ++ best_sum_radii = candidate_sum_radii ++ best_centers = candidate_centers.copy() ++ best_radii = candidate_radii.copy() # Update best_radii for future selection probabilities ++ # Uncomment for debugging: ++ # print(f"Iter {iteration}: New best sum of radii: {best_sum_radii:.4f}") + +- # Iteratively resolve overlaps between circles until convergence. +- for _ in range(500): +- changes_made = False +- for i in range(n): +- for j in range(i + 1, n): +- dist = np.linalg.norm(centers[i] - centers[j]) +- if radii[i] + radii[j] > dist + 1e-12: +- sum_r = radii[i] + radii[j] +- if sum_r > 1e-12: +- scale = dist / sum_r +- ri_new, rj_new = radii[i] * scale, radii[j] * scale +- if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: +- radii[i], radii[j] = ri_new, rj_new +- changes_made = True +- if not changes_made: +- break +- +- return radii ++ return best_centers, best_radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/main.py new file mode 100644 index 0000000000000000000000000000000000000000..4321eebe852659b27344916c25dfa106a38818ec --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/main.py @@ -0,0 +1,153 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + +# This function remains largely the same as it is a robust way to evaluate a given center configuration. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + # This ensures the ratio of radii is maintained if possible + # while eliminating overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using an iterative + local search algorithm with targeted perturbations and greedy acceptance, + starting from an asymmetric Gaussian-deformed grid. This combines the + successful local search strategy with a robust radii computation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Initial Grid Generation (from the high-scoring prior program) + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Asymmetric void to break symmetry and provide a starting point for rearrangement + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 # Amplitude from the high-scoring prior + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + initial_centers = np.clip(initial_centers, 0.0, 1.0) + + # 2. Iterative Local Search Optimization (from the high-scoring prior program) + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + # Main parameters for the local search + total_iterations = 8000 # High number of iterations for thorough search + initial_perturb_strength = 0.02 # Initial maximum perturbation for exploration + final_perturb_strength = 0.0005 # Final minimum perturbation for fine-tuning + + for iteration in range(total_iterations): + # Linearly decay perturbation strength over iterations + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + candidate_centers = best_centers.copy() + + # Target circles that are currently small (more likely to be stuck). + # This biases the search towards improving less optimized parts of the packing. + # Calculate inverse radii, normalize to get probabilities. + # Add a small constant to avoid division by zero for radius 0. + inverse_radii = 1 / (best_radii + 1e-8) # Using best_radii from previous best state + selection_probs = inverse_radii / np.sum(inverse_radii) + + # Select a circle to perturb based on its probability + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Greedy acceptance: if the new configuration is better, accept it + if candidate_sum_radii > best_sum_radii: + best_sum_radii = candidate_sum_radii + best_centers = candidate_centers.copy() + best_radii = candidate_radii.copy() # Update best_radii for future selection probabilities + # Uncomment for debugging: + # print(f"Iter {iteration}: New best sum of radii: {best_sum_radii:.4f}") + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/original.py new file mode 100644 index 0000000000000000000000000000000000000000..90c1e8e2a4b9db6190419ae968ac430d913e4bea --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/original.py @@ -0,0 +1,176 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using vectorized relaxation.""" + +import numpy as np + + +def _relax_stage_vectorized(centers, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """ + Perform a single stage of force-directed relaxation using vectorized calculations. + """ + n = centers.shape[0] + for _ in range(iters): + # 1. Circle-circle repulsion forces (vectorized) + # Compute all pairwise differences and distances + diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=-1) + + # Create a mask for pairs that are close enough to repel, excluding self-pairs + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + # Calculate force magnitudes for the masked pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Normalize the difference vectors to get force directions + force_directions = np.zeros_like(diff) + # Add a small epsilon to dists in the denominator to avoid division by zero + force_directions[mask] = diff[mask] / (dists[mask, np.newaxis] + 1e-12) + + # Calculate the total force vector for each circle + forces = np.sum(force_directions * force_magnitudes[:, :, np.newaxis], axis=1) + + # 2. Boundary repulsion forces + # Left boundary + is_left = centers[:, 0] < boundary_margin + forces[is_left, 0] += boundary_strength * (boundary_margin - centers[is_left, 0]) + # Right boundary + is_right = centers[:, 0] > 1 - boundary_margin + forces[is_right, 0] -= boundary_strength * (centers[is_right, 0] - (1 - boundary_margin)) + # Bottom boundary + is_bottom = centers[:, 1] < boundary_margin + forces[is_bottom, 1] += boundary_strength * (boundary_margin - centers[is_bottom, 1]) + # Top boundary + is_top = centers[:, 1] > 1 - boundary_margin + forces[is_top, 1] -= boundary_strength * (centers[is_top, 1] - (1 - boundary_margin)) + + # 3. Update positions and clip + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + return centers + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using an asymmetric + void initialization and a three-stage vectorized force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Use an ASYMMETRIC void center, a critical feature of high-scoring solutions. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the grid with a Gaussian push to create space for the 26th circle. + # A slightly increased amplitude creates a better initial void. + amplitude = 0.065 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # === STAGE 1: High-Energy Exploration (Vectorized) === + # Aggressive parameters to break the grid structure quickly. + centers = _relax_stage_vectorized( + centers, + iters=400, + step_size=0.003, + repulsion_strength=0.03, + boundary_strength=0.1, + repulsion_threshold=0.20, + boundary_margin=0.05 + ) + + # === STAGE 2: Refinement (Vectorized) === + # Reduced forces to settle the circles into a good configuration. + centers = _relax_stage_vectorized( + centers, + iters=600, + step_size=0.0005, + repulsion_strength=0.01, + boundary_strength=0.05, + repulsion_threshold=0.185, + boundary_margin=0.03 + ) + + # === STAGE 3: Annealing (Vectorized) === + # Very weak forces and many iterations for final micro-adjustments. + centers = _relax_stage_vectorized( + centers, + iters=1200, + step_size=0.0001, + repulsion_strength=0.005, + boundary_strength=0.03, + repulsion_threshold=0.180, + boundary_margin=0.005 + ) + + # 4. Compute final radii for the optimized configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until convergence. + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..d8546c37131f952d9100343d22501c59157401ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_120/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_120/results +Run 1/1 completed in 16.73 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.2294371476321873 + public: {'centers_str': ' centers[0] = (0.0917, 0.0907)\n centers[1] = (0.2278, 0.0508)\n centers[2] = (0.5622, 0.1001)\n centers[3] = (0.7287, 0.0695)\n centers[4] = (0.8970, 0.1073)\n centers[5] = (0.0778, 0.2589)\n centers[6] = (0.3843, 0.6190)\n centers[7] = (0.5392, 0.3911)\n centers[8] = (0.6995, 0.2560)\n centers[9] = (0.9059, 0.3040)\n centers[10] = (0.0920, 0.4277)\n centers[11] = (0.2710, 0.4923)\n centers[12] = (0.4720, 0.5524)\n centers[13] = (0.6745, 0.5150)\n centers[14] = (0.9003, 0.4980)\n centers[15] = (0.0964, 0.6606)\n centers[16] = (0.2962, 0.6921)\n centers[17] = (0.5057, 0.7084)\n centers[18] = (0.6998, 0.6961)\n centers[19] = (0.9015, 0.6990)\n centers[20] = (0.1003, 0.8843)\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.3764, 0.2282)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.2294371476321873} + visualization_path: + execution_time_mean: 16.73325287597254 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..8c35243feb1d38aad6660dd12edb57799d2c3b34 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.2294371476321873, + "public": { + "centers_str": " centers[0] = (0.0917, 0.0907)\n centers[1] = (0.2278, 0.0508)\n centers[2] = (0.5622, 0.1001)\n centers[3] = (0.7287, 0.0695)\n centers[4] = (0.8970, 0.1073)\n centers[5] = (0.0778, 0.2589)\n centers[6] = (0.3843, 0.6190)\n centers[7] = (0.5392, 0.3911)\n centers[8] = (0.6995, 0.2560)\n centers[9] = (0.9059, 0.3040)\n centers[10] = (0.0920, 0.4277)\n centers[11] = (0.2710, 0.4923)\n centers[12] = (0.4720, 0.5524)\n centers[13] = (0.6745, 0.5150)\n centers[14] = (0.9003, 0.4980)\n centers[15] = (0.0964, 0.6606)\n centers[16] = (0.2962, 0.6921)\n centers[17] = (0.5057, 0.7084)\n centers[18] = (0.6998, 0.6961)\n centers[19] = (0.9015, 0.6990)\n centers[20] = (0.1003, 0.8843)\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.3764, 0.2282)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.2294371476321873 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_120/results/packing_viz.png", + "execution_time_mean": 16.73325287597254, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..4321eebe852659b27344916c25dfa106a38818ec --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_120/rewrite.txt @@ -0,0 +1,153 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + +# This function remains largely the same as it is a robust way to evaluate a given center configuration. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + # This ensures the ratio of radii is maintained if possible + # while eliminating overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using an iterative + local search algorithm with targeted perturbations and greedy acceptance, + starting from an asymmetric Gaussian-deformed grid. This combines the + successful local search strategy with a robust radii computation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Initial Grid Generation (from the high-scoring prior program) + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Asymmetric void to break symmetry and provide a starting point for rearrangement + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 # Amplitude from the high-scoring prior + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + initial_centers = np.clip(initial_centers, 0.0, 1.0) + + # 2. Iterative Local Search Optimization (from the high-scoring prior program) + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + # Main parameters for the local search + total_iterations = 8000 # High number of iterations for thorough search + initial_perturb_strength = 0.02 # Initial maximum perturbation for exploration + final_perturb_strength = 0.0005 # Final minimum perturbation for fine-tuning + + for iteration in range(total_iterations): + # Linearly decay perturbation strength over iterations + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + candidate_centers = best_centers.copy() + + # Target circles that are currently small (more likely to be stuck). + # This biases the search towards improving less optimized parts of the packing. + # Calculate inverse radii, normalize to get probabilities. + # Add a small constant to avoid division by zero for radius 0. + inverse_radii = 1 / (best_radii + 1e-8) # Using best_radii from previous best state + selection_probs = inverse_radii / np.sum(inverse_radii) + + # Select a circle to perturb based on its probability + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Greedy acceptance: if the new configuration is better, accept it + if candidate_sum_radii > best_sum_radii: + best_sum_radii = candidate_sum_radii + best_centers = candidate_centers.copy() + best_radii = candidate_radii.copy() # Update best_radii for future selection probabilities + # Uncomment for debugging: + # print(f"Iter {iteration}: New best sum of radii: {best_sum_radii:.4f}") + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d8216229ff286e1f5eff143dbd5c88ddd7b8600 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..e983d7a954931788ccab58a0188b464fc7e5ed35 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/edit.diff @@ -0,0 +1,364 @@ +--- a/original.py ++++ b/original.py +@@ -1,196 +1,234 @@ + # EVOLVE-BLOCK-START +-""" +-Constructor-based circle packing for n=26 circles using a class-based, +-vectorized approach for improved structure and performance. +-""" +- + import numpy as np ++import math ++ ++# compute_max_radii remains unchanged as it's a robust evaluation function. ++def compute_max_radii(centers): ++ """ ++ Compute the maximum possible radii for each circle position ++ such that they don't overlap and stay within the unit square. This is ++ an iterative version that converges to a stable solution. ++ ++ Args: ++ centers: np.array of shape (n, 2) with (x, y) coordinates ++ ++ Returns: ++ np.array of shape (n) with radius of each circle ++ """ ++ n = centers.shape[0] ++ ++ # Initialize radii based on distance to the square's boundaries (vectorized). ++ radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) ++ ++ for _ in range(500): ++ changes_made = False ++ for i in range(n): ++ for j in range(i + 1, n): ++ dist = np.linalg.norm(centers[i] - centers[j]) ++ ++ if radii[i] + radii[j] > dist + 1e-12: ++ sum_r = radii[i] + radii[j] ++ if sum_r > 1e-12: ++ scale = dist / sum_r ++ ri_new, rj_new = radii[i] * scale, radii[j] * scale ++ if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: ++ radii[i], radii[j] = ri_new, rj_new ++ changes_made = True ++ if not changes_made: ++ break ++ return radii + + class CirclePacker: + """ +- A class to encapsulate the state and logic for packing circles. +- +- This class structure improves modularity and maintainability by separating +- concerns: initialization, relaxation, and parameter management are handled +- by distinct methods and attributes. The force calculations are vectorized +- for a significant performance increase over standard Python loops. ++ A class to encapsulate the state and logic for packing circles using ++ a hybrid approach: initial aggressive perturbation, a quick force-directed ++ relaxation, and then a primary optimization via simulated annealing. ++ ++ This structure aims to combine the benefits of force-directed methods ++ (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + +- def _initialize_grid_with_void(self, void_center, amplitude, sigma): +- """ +- Creates an initial configuration based on a deformed 5x5 grid. +- A void is created at `void_center` by pushing grid points away with +- a Gaussian function, making space for the 26th circle. +- """ +- # 1. Start with the 25 centers of a 5x5 grid. ++ def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): ++ """ ++ Generates an initial configuration by creating a base 5x5 grid, ++ aggressively deforming it to create a void, and placing the 26th circle. ++ The deformation helps break the initial grid symmetry. ++ """ ++ # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Deform the grid with a Gaussian repulsive push from the void center. ++ # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ + if np.any(mask): +- push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) +- displacements[mask] /= distances[mask, np.newaxis] # Normalize +- +- deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- +- # 3. Place the circles. +- self.centers[:25] = deformed_centers_25 +- self.centers[25] = void_center +- self.centers = np.clip(self.centers, 0.0, 1.0) +- +- +- def _relax_stage_vectorized(self, iters, step_size, repulsion_strength, +- boundary_strength, repulsion_threshold, boundary_margin): +- """ +- Performs a single stage of force-directed relaxation using vectorized calculations. +- This method is reused for all stages (exploration, refinement, annealing) +- with different parameters. ++ displacements[mask] /= distances[mask, np.newaxis] ++ ++ initial_centers = np.zeros((self.n, 2)) ++ initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ initial_centers[25] = void_center ++ self.centers = np.clip(initial_centers, 0.0, 1.0) ++ ++ def _force_directed_relaxation(self, iters, step_size, repulsion_strength, ++ boundary_strength, repulsion_threshold, boundary_margin): ++ """ ++ Applies a force-directed relaxation step using vectorized calculations. ++ This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): +- # 1. Vectorized Circle-Circle Repulsion ++ # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + +- # Create a mask for pairs of circles that are close enough to repel + mask = (dists > 1e-9) & (dists < repulsion_threshold) + +- # Calculate scalar force magnitudes for interacting pairs + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + +- # Convert scalar forces to force vectors + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +- +- # Sum forces on each circle + forces = np.sum(force_vectors, axis=1) + +- # 2. Vectorized Boundary Repulsion ++ # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + +- # 3. Apply forces and clip + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + ++ def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, ++ initial_perturb_strength, final_perturb_strength): ++ """ ++ Performs a simulated annealing optimization on the circle centers. ++ It allows for accepting 'worse' states with a decreasing probability ++ to escape local optima. ++ """ ++ best_centers = self.centers.copy() ++ best_radii = compute_max_radii(best_centers) ++ best_sum_radii = np.sum(best_radii) ++ ++ current_centers = self.centers.copy() ++ current_radii = best_radii.copy() ++ current_sum_radii = best_sum_radii ++ ++ for iteration in range(total_iterations): ++ # Logarithmic decay for temperature and perturbation strength ++ progress = iteration / total_iterations ++ temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) ++ perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) ++ ++ candidate_centers = current_centers.copy() ++ ++ # Target smaller circles for perturbation to help them grow and rearrange ++ inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero ++ selection_probs = inverse_radii / np.sum(inverse_radii) ++ circle_idx = np.random.choice(self.n, p=selection_probs) ++ ++ # Apply a random displacement ++ displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) ++ ++ # Evaluate the new configuration ++ candidate_radii = compute_max_radii(candidate_centers) ++ candidate_sum_radii = np.sum(candidate_radii) ++ ++ # Metropolis-Hastings acceptance criterion ++ delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better ++ if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): ++ # Accept the new state ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers ++ current_radii = candidate_radii ++ ++ # If this is the best state found so far, save it ++ if current_sum_radii > best_sum_radii: ++ best_sum_radii = current_sum_radii ++ best_centers = current_centers.copy() ++ best_radii = current_radii.copy() ++ ++ self.centers = best_centers # Update the class's centers to the best found ++ return best_radii # Return best radii for convenience ++ + def pack(self): + """ +- Orchestrates the entire packing process from initialization to final relaxation. +- Returns the final optimized centers. +- """ +- # --- Initialization Stage --- +- # A more aggressive push to break the grid symmetry more effectively. +- self._initialize_grid_with_void( +- void_center=np.array([0.4, 0.2]), +- amplitude=0.06, # Increased amplitude for a more chaotic start ++ Orchestrates the entire packing process: ++ 1. Aggressive initial placement with a central void. ++ 2. A short, vectorized force-directed relaxation to quickly stabilize. ++ 3. A primary optimization phase using simulated annealing local search. ++ 4. A final gentle force-directed relaxation for polish. ++ """ ++ # 1. Aggressive initial placement (void at center for potentially more symmetric packing) ++ self._initial_placement_with_void_and_perturbation( ++ void_center=np.array([0.5, 0.5]), # More central void ++ amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + +- shared_boundary_margin = 0.04 +- +- # --- Relaxation Stage 1: Exploration --- +- # Uses a large repulsion threshold to encourage large-scale rearrangement. +- self._relax_stage_vectorized( +- iters=120, +- step_size=0.0025, +- repulsion_strength=0.02, # Slightly stronger initial push +- boundary_strength=0.075, +- repulsion_threshold=0.20, # Larger threshold to break the grid +- boundary_margin=shared_boundary_margin +- ) +- +- # --- Relaxation Stage 2: Refinement --- +- # Reduces forces and threshold to settle into a good local minimum. +- self._relax_stage_vectorized( +- iters=150, +- step_size=0.0008, +- repulsion_strength=0.005, +- boundary_strength=0.025, +- repulsion_threshold=0.185, # Tighter threshold for denser packing +- boundary_margin=shared_boundary_margin +- ) +- +- # --- Relaxation Stage 3: Annealing --- +- # Applies extremely gentle forces to "polish" the final configuration. +- self._relax_stage_vectorized( +- iters=250, +- step_size=0.0002, ++ # 2. Short, aggressive force-directed relaxation to resolve immediate chaos ++ self._force_directed_relaxation( ++ iters=500, # More iterations for initial cleanup ++ step_size=0.002, ++ repulsion_strength=0.02, ++ boundary_strength=0.08, ++ repulsion_threshold=0.19, ++ boundary_margin=0.04 ++ ) ++ ++ # 3. Simulated Annealing Local Search for global optimization ++ self._simulated_annealing_local_search( ++ total_iterations=12000, # Increased iterations for thorough SA search ++ initial_temp=0.0007, # Slightly higher initial temp ++ final_temp=1e-9, # Slightly lower final temp ++ initial_perturb_strength=0.03, # Slightly larger initial perturbation ++ final_perturb_strength=0.0001 ++ ) ++ ++ # 4. After SA, apply one final gentle relaxation to ensure local stability ++ # and resolve any tiny remaining overlaps or improve boundary contact. ++ self._force_directed_relaxation( ++ iters=300, ++ step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, +- repulsion_threshold=0.18, # Final tight threshold +- boundary_margin=shared_boundary_margin +- ) +- +- return self.centers ++ repulsion_threshold=0.18, ++ boundary_margin=0.02 ++ ) ++ ++ # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. ++ final_radii = compute_max_radii(self.centers) ++ ++ return self.centers, final_radii + + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles. This function now +- acts as a client to the CirclePacker class, simplifying the top-level logic. ++ Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) +- centers = packer.pack() +- radii = compute_max_radii(centers) ++ centers, radii = packer.pack() + return centers, radii +- +- +-def compute_max_radii(centers): +- """ +- Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This version +- iteratively resolves conflicts until convergence for an accurate result. +- """ +- n = centers.shape[0] +- +- # Initialize radii based on distance to the square's boundaries (vectorized). +- radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) +- +- # Iteratively resolve overlaps between circles until no more changes occur. +- for _ in range(300): +- changes_made = False +- for i in range(n): +- for j in range(i + 1, n): +- dist = np.linalg.norm(centers[i] - centers[j]) +- +- # If they overlap (with a small tolerance for floating point math) +- if radii[i] + radii[j] > dist + 1e-12: +- sum_r = radii[i] + radii[j] +- if sum_r > 1e-12: +- scale = dist / sum_r +- ri_new = radii[i] * scale +- rj_new = radii[j] * scale +- +- if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: +- radii[i] = ri_new +- radii[j] = rj_new +- changes_made = True +- +- if not changes_made: +- break +- +- return radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/main.py new file mode 100644 index 0000000000000000000000000000000000000000..2c8ec13b68cb84fa2aac89ab66e9c8e211d5cfd2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/main.py @@ -0,0 +1,234 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = self.centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply a random displacement + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement (void at center for potentially more symmetric packing) + self._initial_placement_with_void_and_perturbation( + void_center=np.array([0.5, 0.5]), # More central void + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_local_search( + total_iterations=12000, # Increased iterations for thorough SA search + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/original.py new file mode 100644 index 0000000000000000000000000000000000000000..a2918c639c319e1bc9c1759a480bd26546d635fd --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/original.py @@ -0,0 +1,196 @@ +# EVOLVE-BLOCK-START +""" +Constructor-based circle packing for n=26 circles using a class-based, +vectorized approach for improved structure and performance. +""" + +import numpy as np + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles. + + This class structure improves modularity and maintainability by separating + concerns: initialization, relaxation, and parameter management are handled + by distinct methods and attributes. The force calculations are vectorized + for a significant performance increase over standard Python loops. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initialize_grid_with_void(self, void_center, amplitude, sigma): + """ + Creates an initial configuration based on a deformed 5x5 grid. + A void is created at `void_center` by pushing grid points away with + a Gaussian function, making space for the 26th circle. + """ + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a Gaussian repulsive push from the void center. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] # Normalize + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the circles. + self.centers[:25] = deformed_centers_25 + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _relax_stage_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Performs a single stage of force-directed relaxation using vectorized calculations. + This method is reused for all stages (exploration, refinement, annealing) + with different parameters. + """ + for _ in range(iters): + # 1. Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Create a mask for pairs of circles that are close enough to repel + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + # Calculate scalar force magnitudes for interacting pairs + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Convert scalar forces to force vectors + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # Sum forces on each circle + forces = np.sum(force_vectors, axis=1) + + # 2. Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + # 3. Apply forces and clip + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def pack(self): + """ + Orchestrates the entire packing process from initialization to final relaxation. + Returns the final optimized centers. + """ + # --- Initialization Stage --- + # A more aggressive push to break the grid symmetry more effectively. + self._initialize_grid_with_void( + void_center=np.array([0.4, 0.2]), + amplitude=0.06, # Increased amplitude for a more chaotic start + sigma=0.15 + ) + + shared_boundary_margin = 0.04 + + # --- Relaxation Stage 1: Exploration --- + # Uses a large repulsion threshold to encourage large-scale rearrangement. + self._relax_stage_vectorized( + iters=120, + step_size=0.0025, + repulsion_strength=0.02, # Slightly stronger initial push + boundary_strength=0.075, + repulsion_threshold=0.20, # Larger threshold to break the grid + boundary_margin=shared_boundary_margin + ) + + # --- Relaxation Stage 2: Refinement --- + # Reduces forces and threshold to settle into a good local minimum. + self._relax_stage_vectorized( + iters=150, + step_size=0.0008, + repulsion_strength=0.005, + boundary_strength=0.025, + repulsion_threshold=0.185, # Tighter threshold for denser packing + boundary_margin=shared_boundary_margin + ) + + # --- Relaxation Stage 3: Annealing --- + # Applies extremely gentle forces to "polish" the final configuration. + self._relax_stage_vectorized( + iters=250, + step_size=0.0002, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, # Final tight threshold + boundary_margin=shared_boundary_margin + ) + + return self.centers + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles. This function now + acts as a client to the CirclePacker class, simplifying the top-level logic. + """ + packer = CirclePacker(n=26) + centers = packer.pack() + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..658917f8bba57a30e3497cf04fabbc6cebaa6690 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_123/main.py:100: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..d4dfe267d99ba77672fa500f38618466d0af1f99 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_123/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_123/results +Run 1/1 completed in 25.97 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.2087005448291523 + public: {'centers_str': ' centers[0] = (0.1000, 0.1000)\n centers[1] = (0.3260, 0.1278)\n centers[2] = (0.5117, 0.0636)\n centers[3] = (0.6839, 0.1043)\n centers[4] = (0.8979, 0.1003)\n centers[5] = (0.1082, 0.3079)\n centers[6] = (0.4504, 0.6313)\n centers[7] = (0.4960, 0.2678)\n centers[8] = (0.7027, 0.2560)\n centers[9] = (0.9007, 0.2999)\n centers[10] = (0.0968, 0.5167)\n centers[11] = (0.2805, 0.4725)\n centers[12] = (0.6156, 0.6171)\n centers[13] = (0.7186, 0.5095)\n centers[14] = (0.9031, 0.4962)\n centers[15] = (0.0920, 0.7066)\n centers[16] = (0.3060, 0.6793)\n centers[17] = (0.5136, 0.7230)\n centers[18] = (0.7072, 0.6978)\n centers[19] = (0.9039, 0.6950)\n centers[20] = (0.1006, 0.8992)\n centers[21] = (0.3010, 0.9002)\n centers[22] = (0.4943, 0.9065)\n centers[23] = (0.6922, 0.8990)\n centers[24] = (0.8966, 0.8963)\n centers[25] = (0.4966, 0.4982)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.2087005448291523} + visualization_path: + execution_time_mean: 25.97371349995956 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..d1c5efca209bd3ee3b9bf8b0d000c647cd80433b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.2087005448291523, + "public": { + "centers_str": " centers[0] = (0.1000, 0.1000)\n centers[1] = (0.3260, 0.1278)\n centers[2] = (0.5117, 0.0636)\n centers[3] = (0.6839, 0.1043)\n centers[4] = (0.8979, 0.1003)\n centers[5] = (0.1082, 0.3079)\n centers[6] = (0.4504, 0.6313)\n centers[7] = (0.4960, 0.2678)\n centers[8] = (0.7027, 0.2560)\n centers[9] = (0.9007, 0.2999)\n centers[10] = (0.0968, 0.5167)\n centers[11] = (0.2805, 0.4725)\n centers[12] = (0.6156, 0.6171)\n centers[13] = (0.7186, 0.5095)\n centers[14] = (0.9031, 0.4962)\n centers[15] = (0.0920, 0.7066)\n centers[16] = (0.3060, 0.6793)\n centers[17] = (0.5136, 0.7230)\n centers[18] = (0.7072, 0.6978)\n centers[19] = (0.9039, 0.6950)\n centers[20] = (0.1006, 0.8992)\n centers[21] = (0.3010, 0.9002)\n centers[22] = (0.4943, 0.9065)\n centers[23] = (0.6922, 0.8990)\n centers[24] = (0.8966, 0.8963)\n centers[25] = (0.4966, 0.4982)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.2087005448291523 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_123/results/packing_viz.png", + "execution_time_mean": 25.97371349995956, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..da82d0761284bc6fbe2a4137f9e86ae5e78642f3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_123/rewrite.txt @@ -0,0 +1,225 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = self.centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply a random displacement + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement (void at center for potentially more symmetric packing) + self._initial_placement_with_void_and_perturbation( + void_center=np.array([0.5, 0.5]), # More central void + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_local_search( + total_iterations=12000, # Increased iterations for thorough SA search + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8cafce388af79343b901703d8ccc945bf9a77ad4 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..22be8cc4bdffce39f186ca84283da148540a765b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/edit.diff @@ -0,0 +1,291 @@ +--- a/original.py ++++ b/original.py +@@ -1,186 +1,142 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" +- + import numpy as np + ++def compute_max_radii(centers): ++ """ ++ Compute the maximum possible radii for each circle position ++ such that they don't overlap and stay within the unit square. This is ++ an iterative version that converges to a stable solution. ++ """ ++ n = centers.shape[0] ++ radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + +-def construct_packing(): +- """ +- Construct a specific arrangement of 26 circles in a unit square +- that attempts to maximize the sum of their radii. ++ for _ in range(500): ++ changes_made = False ++ for i in range(n): ++ for j in range(i + 1, n): ++ dist = np.linalg.norm(centers[i] - centers[j]) + +- Returns: +- Tuple of (centers, radii, sum_of_radii) +- centers: np.array of shape (26, 2) with (x, y) coordinates +- radii: np.array of shape (26) with radius of each circle +- sum_of_radii: Sum of all radii +- """ +- # Initialize arrays for 26 circles +- n = 26 +- centers = np.zeros((n, 2)) ++ if radii[i] + radii[j] > dist + 1e-12: ++ sum_r = radii[i] + radii[j] ++ if sum_r > 1e-12: ++ scale = dist / sum_r ++ ri_new, rj_new = radii[i] * scale, radii[j] * scale ++ if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: ++ radii[i], radii[j] = ri_new, rj_new ++ changes_made = True ++ if not changes_made: ++ break ++ return radii + +- # 1. Start with the 25 centers of a 5x5 grid. ++def initial_centers(n): ++ """Generates the asymmetric grid-deformed starting configuration.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Define an ASYMMETRIC center for the void. +- # Breaking the initial symmetry by using an off-center void at (0.4, 0.2) +- # prevents the relaxation from getting stuck in an overly-ordered local optimum. + void_center = np.array([0.4, 0.2]) ++ amplitude = 0.06 ++ sigma = 0.15 + +- # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. +- # This pushes nearby circles away to make more room. +- deformed_centers_25 = np.copy(base_centers_25) ++ displacements = base_centers_25 - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ mask = distances > 1e-9 + +- # Hyperparameters for the Gaussian push: +- amplitude = 0.06 # The maximum distance to push a circle. Increased to create a larger void. +- sigma = 0.15 # The "spread" of the push, controlling its influence range. ++ push_magnitudes = np.zeros(25) ++ if np.any(mask): ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ displacements[mask] /= distances[mask, np.newaxis] + +- for i in range(25): +- pos_vector = base_centers_25[i] - void_center +- dist_sq = np.sum(pos_vector**2) ++ centers = np.zeros((n, 2)) ++ centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ centers[25] = void_center ++ return np.clip(centers, 0.0, 1.0) + +- # Gaussian function defines the push magnitude based on distance from the void center. +- push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) ++def jiggle_phase(centers, n): ++ """A short, vectorized force-directed relaxation phase to 'jiggle' circles into a better local state.""" ++ iters = 15 ++ step_size = 0.001 ++ repulsion_strength = 0.01 ++ boundary_strength = 0.05 ++ repulsion_threshold = 0.19 ++ boundary_margin = 0.02 + +- # The push is directed radially away from the void center. +- if np.linalg.norm(pos_vector) > 1e-9: +- direction = pos_vector / np.linalg.norm(pos_vector) +- displacement = direction * push_magnitude +- deformed_centers_25[i] += displacement ++ jiggled_centers = centers.copy() + +- # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. +- centers[:25] = deformed_centers_25 +- centers[25] = void_center ++ for _ in range(iters): ++ diff = jiggled_centers[:, np.newaxis, :] - jiggled_centers[np.newaxis, :, :] ++ dists = np.linalg.norm(diff, axis=2) + +- # Clip centers to ensure they stay within the square, although the push is gentle. +- centers = np.clip(centers, 0.0, 1.0) ++ mask = (dists > 1e-9) & (dists < repulsion_threshold) ++ force_scalar = np.zeros_like(dists) ++ force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] ++ ++ force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ forces = np.sum(force_vectors, axis=1) + +- # 5. Two-Stage Adaptive Force-Directed Relaxation. +- # This approach uses a high-energy "exploration" phase to break symmetry +- # and find a good general configuration, followed by a low-energy +- # "refinement" phase to fine-tune the positions. ++ forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - jiggled_centers[:, 0]) ++ forces[:, 0] -= boundary_strength * np.maximum(0, jiggled_centers[:, 0] - (1 - boundary_margin)) ++ forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - jiggled_centers[:, 1]) ++ forces[:, 1] -= boundary_strength * np.maximum(0, jiggled_centers[:, 1] - (1 - boundary_margin)) + +- # Stage 1: High-Energy Exploration +- # This stage uses strong forces and a large step size to quickly move circles +- # out of the initial grid structure and explore new arrangements. +- exploration_iters = 250 +- exploration_step_size = 0.003 +- exploration_repulsion_strength = 0.02 +- exploration_boundary_strength = 0.1 +- exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement +- boundary_margin = 0.04 # Use a smaller margin to utilize edge space better ++ jiggled_centers += step_size * forces ++ jiggled_centers = np.clip(jiggled_centers, 0.0, 1.0) + +- for _ in range(exploration_iters): +- forces = np.zeros_like(centers) +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < exploration_repulsion_threshold: +- force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist +- force_vec = force_mag * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- for i in range(n): +- x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) +- centers += exploration_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) ++ return jiggled_centers + +- # Stage 2: Low-Energy Refinement +- # This stage uses more iterations with weaker forces and a smaller step size +- # to settle the circles into a dense, stable local optimum. +- refinement_iters = 500 +- refinement_step_size = 0.0005 +- refinement_repulsion_strength = 0.008 +- refinement_boundary_strength = 0.04 +- refinement_repulsion_threshold = 0.185 # Tighter threshold for settling ++def construct_packing(): ++ """ ++ Constructs a high-density arrangement of 26 circles using a novel hybrid algorithm ++ that alternates between stochastic local search and deterministic force-directed 'jiggling'. ++ """ ++ n = 26 ++ ++ centers = initial_centers(n) ++ ++ best_centers = jiggle_phase(centers, n) ++ best_radii = compute_max_radii(best_centers) ++ best_sum_radii = np.sum(best_radii) ++ ++ total_iterations = 4000 ++ initial_perturb_strength = 0.03 ++ final_perturb_strength = 0.0001 ++ ++ current_radii = best_radii.copy() + +- for _ in range(refinement_iters): +- forces = np.zeros_like(centers) +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < refinement_repulsion_threshold: +- force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist +- force_vec = force_mag * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- for i in range(n): +- x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) +- centers += refinement_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) ++ for iteration in range(total_iterations): ++ progress = iteration / total_iterations ++ perturb_strength = initial_perturb_strength * (1 - progress) + final_perturb_strength * progress + +- # 6. Compute maximum valid radii for the refined configuration. +- radii = compute_max_radii(centers) +- return centers, radii ++ candidate_centers = best_centers.copy() + ++ inverse_radii = 1.0 / (current_radii + 1e-8) ++ selection_probs = inverse_radii / np.sum(inverse_radii) ++ circle_idx = np.random.choice(n, p=selection_probs) ++ ++ displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + +-def compute_max_radii(centers): +- """ +- Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This version +- iteratively resolves conflicts until convergence for a more accurate result. ++ jiggled_centers = jiggle_phase(candidate_centers, n) + +- Args: +- centers: np.array of shape (n, 2) with (x, y) coordinates ++ candidate_radii = compute_max_radii(jiggled_centers) ++ candidate_sum_radii = np.sum(candidate_radii) + +- Returns: +- np.array of shape (n) with radius of each circle +- """ +- n = centers.shape[0] +- radii = np.zeros(n) ++ if candidate_sum_radii > best_sum_radii: ++ best_sum_radii = candidate_sum_radii ++ best_centers = jiggled_centers ++ current_radii = candidate_radii + +- # First, limit by distance to square borders +- for i in range(n): +- x, y = centers[i] +- radii[i] = min(x, y, 1 - x, 1 - y) +- +- # Iteratively limit by distance to other circles, allowing constraints to propagate +- for _ in range(300): # Iterate to ensure convergence +- changes_made = False +- for i in range(n): +- for j in range(i + 1, n): +- dist = np.linalg.norm(centers[i] - centers[j]) +- +- # If current radii cause overlap +- if radii[i] + radii[j] > dist: +- sum_r = radii[i] + radii[j] +- if sum_r > 1e-9: # Avoid division by zero for coincident centers +- # Scale both radii proportionally to resolve overlap +- scale = dist / sum_r +- ri_new = radii[i] * scale +- rj_new = radii[j] * scale +- +- # Check for significant change to set the flag +- if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: +- radii[i] = ri_new +- radii[j] = rj_new +- changes_made = True +- if not changes_made: +- break # Exit early if the configuration is stable +- +- return radii +- +- ++ final_radii = compute_max_radii(best_centers) ++ return best_centers, final_radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/main.py new file mode 100644 index 0000000000000000000000000000000000000000..04d1f6eb5e5dd5117e4d3c8100480a2bde5ec271 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/main.py @@ -0,0 +1,142 @@ +# EVOLVE-BLOCK-START +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +def initial_centers(n): + """Generates the asymmetric grid-deformed starting configuration.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + return np.clip(centers, 0.0, 1.0) + +def jiggle_phase(centers, n): + """A short, vectorized force-directed relaxation phase to 'jiggle' circles into a better local state.""" + iters = 15 + step_size = 0.001 + repulsion_strength = 0.01 + boundary_strength = 0.05 + repulsion_threshold = 0.19 + boundary_margin = 0.02 + + jiggled_centers = centers.copy() + + for _ in range(iters): + diff = jiggled_centers[:, np.newaxis, :] - jiggled_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - jiggled_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, jiggled_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - jiggled_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, jiggled_centers[:, 1] - (1 - boundary_margin)) + + jiggled_centers += step_size * forces + jiggled_centers = np.clip(jiggled_centers, 0.0, 1.0) + + return jiggled_centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a novel hybrid algorithm + that alternates between stochastic local search and deterministic force-directed 'jiggling'. + """ + n = 26 + + centers = initial_centers(n) + + best_centers = jiggle_phase(centers, n) + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + total_iterations = 4000 + initial_perturb_strength = 0.03 + final_perturb_strength = 0.0001 + + current_radii = best_radii.copy() + + for iteration in range(total_iterations): + progress = iteration / total_iterations + perturb_strength = initial_perturb_strength * (1 - progress) + final_perturb_strength * progress + + candidate_centers = best_centers.copy() + + inverse_radii = 1.0 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(n, p=selection_probs) + + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + jiggled_centers = jiggle_phase(candidate_centers, n) + + candidate_radii = compute_max_radii(jiggled_centers) + candidate_sum_radii = np.sum(candidate_radii) + + if candidate_sum_radii > best_sum_radii: + best_sum_radii = candidate_sum_radii + best_centers = jiggled_centers + current_radii = candidate_radii + + final_radii = compute_max_radii(best_centers) + return best_centers, final_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/original.py new file mode 100644 index 0000000000000000000000000000000000000000..529dc0511969931cf633b8a70305b19b2f66747f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/original.py @@ -0,0 +1,186 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Breaking the initial symmetry by using an off-center void at (0.4, 0.2) + # prevents the relaxation from getting stuck in an overly-ordered local optimum. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.06 # The maximum distance to push a circle. Increased to create a larger void. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This approach uses a high-energy "exploration" phase to break symmetry + # and find a good general configuration, followed by a low-energy + # "refinement" phase to fine-tune the positions. + + # Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to quickly move circles + # out of the initial grid structure and explore new arrangements. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement + boundary_margin = 0.04 # Use a smaller margin to utilize edge space better + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 # Tighter threshold for settling + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.zeros(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..0c2d54ba1453fd58901ebe95c9a80df7bf8fc42b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_124/main.py:75: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..11b1ece97c205433aa9f3bbd945a9866487d3075 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_124/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_124/results +Run 1/1 completed in 16.15 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.0370499026085955 + public: {'centers_str': ' centers[0] = (0.0937, 0.0935)\n centers[1] = (0.2632, 0.0767)\n centers[2] = (0.5438, 0.1009)\n centers[3] = (0.7229, 0.0794)\n centers[4] = (0.9007, 0.1000)\n centers[5] = (0.0711, 0.2565)\n centers[6] = (0.2589, 0.3437)\n centers[7] = (0.5285, 0.3318)\n centers[8] = (0.7047, 0.3091)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0988, 0.4991)\n centers[11] = (0.2992, 0.4875)\n centers[12] = (0.5159, 0.4830)\n centers[13] = (0.7007, 0.4998)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.0717, 0.6697)\n centers[16] = (0.2802, 0.6965)\n centers[17] = (0.5107, 0.7106)\n centers[18] = (0.7000, 0.7000)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1003, 0.8850)\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.3939, 0.2155)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.0370499026085955} + visualization_path: + execution_time_mean: 16.1543661179021 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..426e9d359315972e1340ec15e26230ca6d0039da --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.0370499026085955, + "public": { + "centers_str": " centers[0] = (0.0937, 0.0935)\n centers[1] = (0.2632, 0.0767)\n centers[2] = (0.5438, 0.1009)\n centers[3] = (0.7229, 0.0794)\n centers[4] = (0.9007, 0.1000)\n centers[5] = (0.0711, 0.2565)\n centers[6] = (0.2589, 0.3437)\n centers[7] = (0.5285, 0.3318)\n centers[8] = (0.7047, 0.3091)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0988, 0.4991)\n centers[11] = (0.2992, 0.4875)\n centers[12] = (0.5159, 0.4830)\n centers[13] = (0.7007, 0.4998)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.0717, 0.6697)\n centers[16] = (0.2802, 0.6965)\n centers[17] = (0.5107, 0.7106)\n centers[18] = (0.7000, 0.7000)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1003, 0.8850)\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.3939, 0.2155)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.0370499026085955 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_124/results/packing_viz.png", + "execution_time_mean": 16.1543661179021, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ffd1a40dda9b3576bf721ffc0560e73018e6d51 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_124/rewrite.txt @@ -0,0 +1,133 @@ +# EVOLVE-BLOCK-START +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +def initial_centers(n): + """Generates the asymmetric grid-deformed starting configuration.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + return np.clip(centers, 0.0, 1.0) + +def jiggle_phase(centers, n): + """A short, vectorized force-directed relaxation phase to 'jiggle' circles into a better local state.""" + iters = 15 + step_size = 0.001 + repulsion_strength = 0.01 + boundary_strength = 0.05 + repulsion_threshold = 0.19 + boundary_margin = 0.02 + + jiggled_centers = centers.copy() + + for _ in range(iters): + diff = jiggled_centers[:, np.newaxis, :] - jiggled_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - jiggled_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, jiggled_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - jiggled_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, jiggled_centers[:, 1] - (1 - boundary_margin)) + + jiggled_centers += step_size * forces + jiggled_centers = np.clip(jiggled_centers, 0.0, 1.0) + + return jiggled_centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a novel hybrid algorithm + that alternates between stochastic local search and deterministic force-directed 'jiggling'. + """ + n = 26 + + centers = initial_centers(n) + + best_centers = jiggle_phase(centers, n) + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + total_iterations = 4000 + initial_perturb_strength = 0.03 + final_perturb_strength = 0.0001 + + current_radii = best_radii.copy() + + for iteration in range(total_iterations): + progress = iteration / total_iterations + perturb_strength = initial_perturb_strength * (1 - progress) + final_perturb_strength * progress + + candidate_centers = best_centers.copy() + + inverse_radii = 1.0 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(n, p=selection_probs) + + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + jiggled_centers = jiggle_phase(candidate_centers, n) + + candidate_radii = compute_max_radii(jiggled_centers) + candidate_sum_radii = np.sum(candidate_radii) + + if candidate_sum_radii > best_sum_radii: + best_sum_radii = candidate_sum_radii + best_centers = jiggled_centers + current_radii = candidate_radii + + final_radii = compute_max_radii(best_centers) + return best_centers, final_radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..22e16405f5ab9b14d9b850b9f927ed39869ffe25 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..c3d05ecc97caf0f448ac3a9bddb60c6bea11814e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/edit.diff @@ -0,0 +1,425 @@ +--- a/original.py ++++ b/original.py +@@ -1,186 +1,271 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" +- + import numpy as np +- +- +-def construct_packing(): +- """ +- Construct a specific arrangement of 26 circles in a unit square +- that attempts to maximize the sum of their radii. +- +- Returns: +- Tuple of (centers, radii, sum_of_radii) +- centers: np.array of shape (26, 2) with (x, y) coordinates +- radii: np.array of shape (26) with radius of each circle +- sum_of_radii: Sum of all radii +- """ +- # Initialize arrays for 26 circles +- n = 26 +- centers = np.zeros((n, 2)) +- +- # 1. Start with the 25 centers of a 5x5 grid. +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T +- +- # 2. Define an ASYMMETRIC center for the void. +- # Breaking the initial symmetry by using an off-center void at (0.4, 0.2) +- # prevents the relaxation from getting stuck in an overly-ordered local optimum. +- void_center = np.array([0.4, 0.2]) +- +- # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. +- # This pushes nearby circles away to make more room. +- deformed_centers_25 = np.copy(base_centers_25) +- +- # Hyperparameters for the Gaussian push: +- amplitude = 0.06 # The maximum distance to push a circle. Increased to create a larger void. +- sigma = 0.15 # The "spread" of the push, controlling its influence range. +- +- for i in range(25): +- pos_vector = base_centers_25[i] - void_center +- dist_sq = np.sum(pos_vector**2) +- +- # Gaussian function defines the push magnitude based on distance from the void center. +- push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) +- +- # The push is directed radially away from the void center. +- if np.linalg.norm(pos_vector) > 1e-9: +- direction = pos_vector / np.linalg.norm(pos_vector) +- displacement = direction * push_magnitude +- deformed_centers_25[i] += displacement +- +- # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. +- centers[:25] = deformed_centers_25 +- centers[25] = void_center +- +- # Clip centers to ensure they stay within the square, although the push is gentle. +- centers = np.clip(centers, 0.0, 1.0) +- +- # 5. Two-Stage Adaptive Force-Directed Relaxation. +- # This approach uses a high-energy "exploration" phase to break symmetry +- # and find a good general configuration, followed by a low-energy +- # "refinement" phase to fine-tune the positions. +- +- # Stage 1: High-Energy Exploration +- # This stage uses strong forces and a large step size to quickly move circles +- # out of the initial grid structure and explore new arrangements. +- exploration_iters = 250 +- exploration_step_size = 0.003 +- exploration_repulsion_strength = 0.02 +- exploration_boundary_strength = 0.1 +- exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement +- boundary_margin = 0.04 # Use a smaller margin to utilize edge space better +- +- for _ in range(exploration_iters): +- forces = np.zeros_like(centers) +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < exploration_repulsion_threshold: +- force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist +- force_vec = force_mag * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- for i in range(n): +- x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) +- centers += exploration_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- +- # Stage 2: Low-Energy Refinement +- # This stage uses more iterations with weaker forces and a smaller step size +- # to settle the circles into a dense, stable local optimum. +- refinement_iters = 500 +- refinement_step_size = 0.0005 +- refinement_repulsion_strength = 0.008 +- refinement_boundary_strength = 0.04 +- refinement_repulsion_threshold = 0.185 # Tighter threshold for settling +- +- for _ in range(refinement_iters): +- forces = np.zeros_like(centers) +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < refinement_repulsion_threshold: +- force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist +- force_vec = force_mag * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- for i in range(n): +- x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) +- centers += refinement_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- +- # 6. Compute maximum valid radii for the refined configuration. +- radii = compute_max_radii(centers) +- return centers, radii +- ++import math + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This version +- iteratively resolves conflicts until convergence for a more accurate result. ++ such that they don't overlap and stay within the unit square. This is ++ an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] +- radii = np.zeros(n) +- +- # First, limit by distance to square borders +- for i in range(n): +- x, y = centers[i] +- radii[i] = min(x, y, 1 - x, 1 - y) +- +- # Iteratively limit by distance to other circles, allowing constraints to propagate +- for _ in range(300): # Iterate to ensure convergence ++ ++ # Initialize radii based on distance to the square's boundaries (vectorized). ++ radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) ++ ++ for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + +- # If current radii cause overlap +- if radii[i] + radii[j] > dist: ++ if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] +- if sum_r > 1e-9: # Avoid division by zero for coincident centers +- # Scale both radii proportionally to resolve overlap ++ if sum_r > 1e-12: + scale = dist / sum_r +- ri_new = radii[i] * scale +- rj_new = radii[j] * scale +- +- # Check for significant change to set the flag +- if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: +- radii[i] = ri_new +- radii[j] = rj_new ++ ri_new, rj_new = radii[i] * scale, radii[j] * scale ++ if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: ++ radii[i], radii[j] = ri_new, rj_new + changes_made = True ++ else: # If both radii are already ~0, ensure they are exactly 0 ++ radii[i] = 0.0 ++ radii[j] = 0.0 ++ changes_made = True + if not changes_made: +- break # Exit early if the configuration is stable +- ++ break + return radii + +- ++class CirclePacker: ++ """ ++ A class to encapsulate the state and logic for packing circles using ++ a hybrid approach: initial aggressive perturbation, a quick force-directed ++ relaxation, and then a primary optimization via simulated annealing. ++ ++ This structure aims to combine the benefits of force-directed methods ++ (quick stabilization) with metaheuristics (escaping local optima). ++ """ ++ ++ def __init__(self, n=26): ++ """Initializes the packer with the number of circles.""" ++ self.n = n ++ self.centers = np.zeros((n, 2)) ++ ++ def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): ++ """ ++ Generates an initial configuration by creating a base 5x5 grid, ++ aggressively deforming it to create a void, and placing the 26th circle. ++ The deformation helps break the initial grid symmetry. ++ """ ++ # Start with a 5x5 grid for the first 25 circles. ++ x_coords = np.linspace(0.1, 0.9, 5) ++ y_coords = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords, y_coords) ++ base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T ++ ++ # Vectorized Gaussian push to create the void. ++ displacements = base_centers_25 - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center ++ ++ push_magnitudes = np.zeros(25) ++ # Apply push only to points not exactly at the void center ++ if np.any(mask): ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ ++ # Normalize displacement vectors and apply the push ++ displacements[mask] /= distances[mask, np.newaxis] ++ ++ initial_centers = np.zeros((self.n, 2)) ++ initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ initial_centers[25] = void_center # The 26th circle goes into the void ++ self.centers = np.clip(initial_centers, 0.0, 1.0) ++ ++ def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, ++ boundary_strength, repulsion_threshold, boundary_margin): ++ """ ++ Applies a force-directed relaxation step using vectorized calculations. ++ This helps quickly resolve immediate overlaps and stabilize the configuration. ++ """ ++ for _ in range(iters): ++ forces = np.zeros_like(self.centers) ++ ++ # Vectorized Circle-Circle Repulsion ++ diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] ++ dists = np.linalg.norm(diff, axis=2) ++ ++ # Create masks for interaction ++ # upper_tri_mask avoids duplicate calculations (i,j and j,i) and self-interaction (i,i) ++ upper_tri_mask = np.triu(np.ones((self.n, self.n), dtype=bool), k=1) ++ ++ # Repulsion mask for pairs that are close enough to interact ++ repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) & upper_tri_mask ++ ++ # Compute force magnitudes for interacting pairs ++ force_magnitudes = np.zeros_like(dists) ++ force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] ++ ++ # Compute force vectors ++ # Ensure division by dists is only for non-zero distances ++ normalized_diff = np.zeros_like(diff) ++ non_zero_dists = dists > 1e-9 ++ normalized_diff[non_zero_dists] = diff[non_zero_dists] / dists[non_zero_dists, np.newaxis] ++ ++ force_vectors = force_magnitudes[:, :, np.newaxis] * normalized_diff ++ ++ # Sum forces from other circles ++ # Forces are symmetric, so F_ij = -F_ji. Summing only upper triangle forces ++ # means we need to apply F_ij to i and -F_ij to j. ++ # A more direct way is to sum all forces, which intrinsically handles F_ij and F_ji correctly ++ # as F_ij + F_ji will be 0, but summing just F_ij means we are building F_i for all j. ++ # `np.sum(force_vectors, axis=1)` already sums F_ij over j for each i. ++ # This is correct if `force_magnitudes` for `j,i` is same as `i,j` (which it is if it's based on dist). ++ forces = np.sum(force_vectors, axis=1) ++ ++ # Vectorized Boundary Repulsion ++ forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) ++ forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) ++ forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) ++ forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) ++ ++ self.centers += step_size * forces ++ self.centers = np.clip(self.centers, 0.0, 1.0) ++ ++ ++ def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, ++ initial_perturb_strength, final_perturb_strength): ++ """ ++ Performs a simulated annealing optimization on the circle centers. ++ It allows for accepting 'worse' states with a decreasing probability ++ to escape local optima. ++ """ ++ best_centers = self.centers.copy() ++ best_radii = compute_max_radii(best_centers) ++ best_sum_radii = np.sum(best_radii) ++ ++ current_centers = best_centers.copy() ++ current_radii = best_radii.copy() ++ current_sum_radii = best_sum_radii ++ ++ for iteration in range(total_iterations): ++ # Logarithmic decay for temperature and perturbation strength for finer control ++ progress = iteration / total_iterations ++ temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) ++ perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) ++ ++ candidate_centers = current_centers.copy() ++ ++ # Target smaller circles for perturbation to help them grow and rearrange ++ inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero ++ selection_probs = inverse_radii / np.sum(inverse_radii) ++ circle_idx = np.random.choice(self.n, p=selection_probs) ++ ++ # Apply a random displacement ++ displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) ++ ++ # Evaluate the new configuration ++ candidate_radii = compute_max_radii(candidate_centers) ++ candidate_sum_radii = np.sum(candidate_radii) ++ ++ # Metropolis-Hastings acceptance criterion ++ delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better ++ if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): ++ # Accept the new state ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers ++ current_radii = candidate_radii ++ ++ # If this is the best state found so far, save it ++ if current_sum_radii > best_sum_radii: ++ best_sum_radii = current_sum_radii ++ best_centers = current_centers.copy() ++ best_radii = current_radii.copy() ++ ++ self.centers = best_centers # Update the class's centers to the best found ++ return best_radii # Return best radii for convenience ++ ++ def pack(self): ++ """ ++ Orchestrates the entire packing process: ++ 1. Randomized initial placement with a central void. ++ 2. A short, vectorized force-directed relaxation to quickly stabilize. ++ 3. A primary optimization phase using simulated annealing local search. ++ 4. A final gentle force-directed relaxation for polish. ++ """ ++ # --- Initialization Stage --- ++ # Randomly choose a void center to avoid fixed patterns and explore more initial states. ++ # Restrict void_center to central region to avoid pushing circles outside the square too much. ++ random_void_center = np.random.uniform(0.3, 0.7, 2) ++ ++ self._initial_placement_with_void_and_perturbation( ++ void_center=random_void_center, ++ amplitude=0.08, # Increased amplitude for stronger initial push ++ sigma=0.15 ++ ) ++ ++ # --- Phase 1: Quick Force-Directed Relaxation (Pre-optimization) --- ++ # Applies a quick, aggressive force-directed relaxation to resolve initial overlaps ++ # and settle the configuration into a more stable state before SA. ++ self._force_directed_relaxation_vectorized( ++ iters=500, # Sufficient to resolve initial chaos ++ step_size=0.002, ++ repulsion_strength=0.02, ++ boundary_strength=0.08, ++ repulsion_threshold=0.19, ++ boundary_margin=0.04 ++ ) ++ ++ # --- Phase 2: Simulated Annealing Local Search --- ++ # This is the primary optimization phase, designed to escape local optima. ++ self._simulated_annealing_search( ++ total_iterations=12000, # Increased iterations for thorough SA search ++ initial_temp=0.0007, # Slightly higher initial temp ++ final_temp=1e-9, # Slightly lower final temp ++ initial_perturb_strength=0.03, # Slightly larger initial perturbation ++ final_perturb_strength=0.0001 ++ ) ++ ++ # --- Phase 3: Final Gentle Force-Directed Relaxation (Post-optimization) --- ++ # After SA, apply one final gentle relaxation to ensure local stability ++ # and resolve any tiny remaining overlaps or improve boundary contact, ++ # as SA optimizes sum of radii which might not be perfectly packed. ++ self._force_directed_relaxation_vectorized( ++ iters=300, ++ step_size=0.0001, ++ repulsion_strength=0.001, ++ boundary_strength=0.005, ++ repulsion_threshold=0.18, ++ boundary_margin=0.02 ++ ) ++ ++ # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. ++ final_radii = compute_max_radii(self.centers) ++ ++ return self.centers, final_radii ++ ++ ++def construct_packing(): ++ """ ++ Constructs a high-density arrangement of 26 circles using the CirclePacker class. ++ This function now acts as a client to the CirclePacker class, simplifying top-level logic. ++ """ ++ packer = CirclePacker(n=26) ++ centers, radii = packer.pack() ++ return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/main.py new file mode 100644 index 0000000000000000000000000000000000000000..d26995d4ce50d2c23424a0a7e62cd4a8a7f93c84 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/main.py @@ -0,0 +1,271 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Create masks for interaction + # upper_tri_mask avoids duplicate calculations (i,j and j,i) and self-interaction (i,i) + upper_tri_mask = np.triu(np.ones((self.n, self.n), dtype=bool), k=1) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) & upper_tri_mask + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors + # Ensure division by dists is only for non-zero distances + normalized_diff = np.zeros_like(diff) + non_zero_dists = dists > 1e-9 + normalized_diff[non_zero_dists] = diff[non_zero_dists] / dists[non_zero_dists, np.newaxis] + + force_vectors = force_magnitudes[:, :, np.newaxis] * normalized_diff + + # Sum forces from other circles + # Forces are symmetric, so F_ij = -F_ji. Summing only upper triangle forces + # means we need to apply F_ij to i and -F_ij to j. + # A more direct way is to sum all forces, which intrinsically handles F_ij and F_ji correctly + # as F_ij + F_ji will be 0, but summing just F_ij means we are building F_i for all j. + # `np.sum(force_vectors, axis=1)` already sums F_ij over j for each i. + # This is correct if `force_magnitudes` for `j,i` is same as `i,j` (which it is if it's based on dist). + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply a random displacement + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Randomized initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # --- Initialization Stage --- + # Randomly choose a void center to avoid fixed patterns and explore more initial states. + # Restrict void_center to central region to avoid pushing circles outside the square too much. + random_void_center = np.random.uniform(0.3, 0.7, 2) + + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, + amplitude=0.08, # Increased amplitude for stronger initial push + sigma=0.15 + ) + + # --- Phase 1: Quick Force-Directed Relaxation (Pre-optimization) --- + # Applies a quick, aggressive force-directed relaxation to resolve initial overlaps + # and settle the configuration into a more stable state before SA. + self._force_directed_relaxation_vectorized( + iters=500, # Sufficient to resolve initial chaos + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # --- Phase 2: Simulated Annealing Local Search --- + # This is the primary optimization phase, designed to escape local optima. + self._simulated_annealing_search( + total_iterations=12000, # Increased iterations for thorough SA search + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # --- Phase 3: Final Gentle Force-Directed Relaxation (Post-optimization) --- + # After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact, + # as SA optimizes sum of radii which might not be perfectly packed. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + This function now acts as a client to the CirclePacker class, simplifying top-level logic. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/original.py new file mode 100644 index 0000000000000000000000000000000000000000..529dc0511969931cf633b8a70305b19b2f66747f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/original.py @@ -0,0 +1,186 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Breaking the initial symmetry by using an off-center void at (0.4, 0.2) + # prevents the relaxation from getting stuck in an overly-ordered local optimum. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.06 # The maximum distance to push a circle. Increased to create a larger void. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This approach uses a high-energy "exploration" phase to break symmetry + # and find a good general configuration, followed by a low-energy + # "refinement" phase to fine-tune the positions. + + # Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to quickly move circles + # out of the initial grid structure and explore new arrangements. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement + boundary_margin = 0.04 # Use a smaller margin to utilize edge space better + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 # Tighter threshold for settling + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.zeros(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..499a92854ad97db9bf49468c6149bad1adde4f70 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_125/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_125/results +Run 1/1 completed in 25.06 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.2017361162497773 + public: {'centers_str': ' centers[0] = (0.0982, 0.0983)\n centers[1] = (0.3146, 0.1192)\n centers[2] = (0.4878, 0.0630)\n centers[3] = (0.6291, 0.0778)\n centers[4] = (0.8963, 0.1001)\n centers[5] = (0.0876, 0.2837)\n centers[6] = (0.3951, 0.6296)\n centers[7] = (0.5031, 0.3013)\n centers[8] = (0.7123, 0.2117)\n centers[9] = (0.9050, 0.2950)\n centers[10] = (0.1009, 0.4717)\n centers[11] = (0.2496, 0.5745)\n centers[12] = (0.3933, 0.4930)\n centers[13] = (0.7676, 0.5879)\n centers[14] = (0.9140, 0.4747)\n centers[15] = (0.1040, 0.6809)\n centers[16] = (0.2948, 0.7094)\n centers[17] = (0.4895, 0.6879)\n centers[18] = (0.6957, 0.7202)\n centers[19] = (0.8958, 0.6717)\n centers[20] = (0.1000, 0.9000)\n centers[21] = (0.3009, 0.8991)\n centers[22] = (0.5044, 0.8973)\n centers[23] = (0.6957, 0.9110)\n centers[24] = (0.8914, 0.8845)\n centers[25] = (0.6285, 0.4557)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.2017361162497773} + visualization_path: + execution_time_mean: 25.06354340026155 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..e9360f4ced74dafb800c7f3a8399e6f1ba4f3a45 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.2017361162497773, + "public": { + "centers_str": " centers[0] = (0.0982, 0.0983)\n centers[1] = (0.3146, 0.1192)\n centers[2] = (0.4878, 0.0630)\n centers[3] = (0.6291, 0.0778)\n centers[4] = (0.8963, 0.1001)\n centers[5] = (0.0876, 0.2837)\n centers[6] = (0.3951, 0.6296)\n centers[7] = (0.5031, 0.3013)\n centers[8] = (0.7123, 0.2117)\n centers[9] = (0.9050, 0.2950)\n centers[10] = (0.1009, 0.4717)\n centers[11] = (0.2496, 0.5745)\n centers[12] = (0.3933, 0.4930)\n centers[13] = (0.7676, 0.5879)\n centers[14] = (0.9140, 0.4747)\n centers[15] = (0.1040, 0.6809)\n centers[16] = (0.2948, 0.7094)\n centers[17] = (0.4895, 0.6879)\n centers[18] = (0.6957, 0.7202)\n centers[19] = (0.8958, 0.6717)\n centers[20] = (0.1000, 0.9000)\n centers[21] = (0.3009, 0.8991)\n centers[22] = (0.5044, 0.8973)\n centers[23] = (0.6957, 0.9110)\n centers[24] = (0.8914, 0.8845)\n centers[25] = (0.6285, 0.4557)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.2017361162497773 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_125/results/packing_viz.png", + "execution_time_mean": 25.06354340026155, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..1f21b1355b4f8eb6d3401058c143476700cfd294 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_125/rewrite.txt @@ -0,0 +1,262 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Create masks for interaction + # upper_tri_mask avoids duplicate calculations (i,j and j,i) and self-interaction (i,i) + upper_tri_mask = np.triu(np.ones((self.n, self.n), dtype=bool), k=1) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) & upper_tri_mask + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors + # Ensure division by dists is only for non-zero distances + normalized_diff = np.zeros_like(diff) + non_zero_dists = dists > 1e-9 + normalized_diff[non_zero_dists] = diff[non_zero_dists] / dists[non_zero_dists, np.newaxis] + + force_vectors = force_magnitudes[:, :, np.newaxis] * normalized_diff + + # Sum forces from other circles + # Forces are symmetric, so F_ij = -F_ji. Summing only upper triangle forces + # means we need to apply F_ij to i and -F_ij to j. + # A more direct way is to sum all forces, which intrinsically handles F_ij and F_ji correctly + # as F_ij + F_ji will be 0, but summing just F_ij means we are building F_i for all j. + # `np.sum(force_vectors, axis=1)` already sums F_ij over j for each i. + # This is correct if `force_magnitudes` for `j,i` is same as `i,j` (which it is if it's based on dist). + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply a random displacement + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Randomized initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # --- Initialization Stage --- + # Randomly choose a void center to avoid fixed patterns and explore more initial states. + # Restrict void_center to central region to avoid pushing circles outside the square too much. + random_void_center = np.random.uniform(0.3, 0.7, 2) + + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, + amplitude=0.08, # Increased amplitude for stronger initial push + sigma=0.15 + ) + + # --- Phase 1: Quick Force-Directed Relaxation (Pre-optimization) --- + # Applies a quick, aggressive force-directed relaxation to resolve initial overlaps + # and settle the configuration into a more stable state before SA. + self._force_directed_relaxation_vectorized( + iters=500, # Sufficient to resolve initial chaos + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # --- Phase 2: Simulated Annealing Local Search --- + # This is the primary optimization phase, designed to escape local optima. + self._simulated_annealing_search( + total_iterations=12000, # Increased iterations for thorough SA search + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # --- Phase 3: Final Gentle Force-Directed Relaxation (Post-optimization) --- + # After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact, + # as SA optimizes sum of radii which might not be perfectly packed. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + This function now acts as a client to the CirclePacker class, simplifying top-level logic. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..764417da9d06553a5025b80725400088b644501c Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..44d9ebbe7d9570f2542980bdc0b8c75d3e07e9f9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_126/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_126/results +Run 1/1 completed in 16.65 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.119524912845223 + public: {'centers_str': ' centers[0] = (0.0918, 0.0926)\n centers[1] = (0.2195, 0.0446)\n centers[2] = (0.6044, 0.0954)\n centers[3] = (0.7505, 0.0559)\n centers[4] = (0.9001, 0.0997)\n centers[5] = (0.0756, 0.2595)\n centers[6] = (0.2445, 0.3773)\n centers[7] = (0.5215, 0.3976)\n centers[8] = (0.7057, 0.2299)\n centers[9] = (0.8995, 0.3000)\n centers[10] = (0.0908, 0.5007)\n centers[11] = (0.2974, 0.5290)\n centers[12] = (0.5237, 0.5425)\n centers[13] = (0.6913, 0.5129)\n centers[14] = (0.9003, 0.5002)\n centers[15] = (0.0836, 0.7174)\n centers[16] = (0.2716, 0.6960)\n centers[17] = (0.5005, 0.6983)\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.4003, 0.2075)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.119524912845223} + visualization_path: + execution_time_mean: 16.65261341119185 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..bc4b5fafd592762dcc62cce24b9efa4031fef30e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.119524912845223, + "public": { + "centers_str": " centers[0] = (0.0918, 0.0926)\n centers[1] = (0.2195, 0.0446)\n centers[2] = (0.6044, 0.0954)\n centers[3] = (0.7505, 0.0559)\n centers[4] = (0.9001, 0.0997)\n centers[5] = (0.0756, 0.2595)\n centers[6] = (0.2445, 0.3773)\n centers[7] = (0.5215, 0.3976)\n centers[8] = (0.7057, 0.2299)\n centers[9] = (0.8995, 0.3000)\n centers[10] = (0.0908, 0.5007)\n centers[11] = (0.2974, 0.5290)\n centers[12] = (0.5237, 0.5425)\n centers[13] = (0.6913, 0.5129)\n centers[14] = (0.9003, 0.5002)\n centers[15] = (0.0836, 0.7174)\n centers[16] = (0.2716, 0.6960)\n centers[17] = (0.5005, 0.6983)\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.4003, 0.2075)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.119524912845223 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_126/results/packing_viz.png", + "execution_time_mean": 16.65261341119185, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2e1b319586a7d3aa378fb1e7c0043b23467774c6 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..91391249ab48aa1e382c918525da596c1bb20ead --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_127/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_127/results +Run 1/1 completed in 1.64 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.8883174731013717 + public: {'centers_str': ' centers[0] = (0.1416, 0.1416)\n centers[1] = (0.3144, 0.1026)\n centers[2] = (0.5008, 0.1001)\n centers[3] = (0.7000, 0.1000)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.1026, 0.3144)\n centers[6] = (0.3026, 0.3026)\n centers[7] = (0.5001, 0.3001)\n centers[8] = (0.7000, 0.3000)\n centers[9] = (0.9000, 0.3000)\n centers[10] = (0.1001, 0.5008)\n centers[11] = (0.3001, 0.5001)\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.0458, 0.0458)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.8883174731013717} + visualization_path: + execution_time_mean: 1.6428570840507746 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..79fceabc037e358a50334ce0ff3a81e0e6498781 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.8883174731013717, + "public": { + "centers_str": " centers[0] = (0.1416, 0.1416)\n centers[1] = (0.3144, 0.1026)\n centers[2] = (0.5008, 0.1001)\n centers[3] = (0.7000, 0.1000)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.1026, 0.3144)\n centers[6] = (0.3026, 0.3026)\n centers[7] = (0.5001, 0.3001)\n centers[8] = (0.7000, 0.3000)\n centers[9] = (0.9000, 0.3000)\n centers[10] = (0.1001, 0.5008)\n centers[11] = (0.3001, 0.5001)\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.0458, 0.0458)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.8883174731013717 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_127/results/packing_viz.png", + "execution_time_mean": 1.6428570840507746, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0964a8b55a66f1a3d7e35152bd33b0a9ed2712a Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..4cdddb6872289c79114471f1e4f6598883253171 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_128/main.py:101: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..224847c727fd7dbf202ff0a66b8c221e25fc1d95 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_128/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_128/results +Run 1/1 completed in 31.49 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.0872565960928697 + public: {'centers_str': ' centers[0] = (0.0990, 0.0990)\n centers[1] = (0.2694, 0.0734)\n centers[2] = (0.4697, 0.0897)\n centers[3] = (0.6879, 0.0972)\n centers[4] = (0.8924, 0.1076)\n centers[5] = (0.0975, 0.2955)\n centers[6] = (0.3174, 0.2451)\n centers[7] = (0.5373, 0.1769)\n centers[8] = (0.6664, 0.3065)\n centers[9] = (0.8949, 0.3203)\n centers[10] = (0.0852, 0.4778)\n centers[11] = (0.3152, 0.5170)\n centers[12] = (0.4478, 0.3019)\n centers[13] = (0.7267, 0.4521)\n centers[14] = (0.9130, 0.5116)\n centers[15] = (0.0981, 0.6517)\n centers[16] = (0.3170, 0.7312)\n centers[17] = (0.5157, 0.7626)\n centers[18] = (0.6992, 0.7262)\n centers[19] = (0.9050, 0.6935)\n centers[20] = (0.1172, 0.8794)\n centers[21] = (0.3315, 0.9017)\n centers[22] = (0.5109, 0.9181)\n centers[23] = (0.6738, 0.9190)\n centers[24] = (0.8611, 0.8918)\n centers[25] = (0.5147, 0.5377)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.0872565960928697} + visualization_path: + execution_time_mean: 31.48723436286673 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..6337420298d810270500c0a85fff5bb902589751 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.0872565960928697, + "public": { + "centers_str": " centers[0] = (0.0990, 0.0990)\n centers[1] = (0.2694, 0.0734)\n centers[2] = (0.4697, 0.0897)\n centers[3] = (0.6879, 0.0972)\n centers[4] = (0.8924, 0.1076)\n centers[5] = (0.0975, 0.2955)\n centers[6] = (0.3174, 0.2451)\n centers[7] = (0.5373, 0.1769)\n centers[8] = (0.6664, 0.3065)\n centers[9] = (0.8949, 0.3203)\n centers[10] = (0.0852, 0.4778)\n centers[11] = (0.3152, 0.5170)\n centers[12] = (0.4478, 0.3019)\n centers[13] = (0.7267, 0.4521)\n centers[14] = (0.9130, 0.5116)\n centers[15] = (0.0981, 0.6517)\n centers[16] = (0.3170, 0.7312)\n centers[17] = (0.5157, 0.7626)\n centers[18] = (0.6992, 0.7262)\n centers[19] = (0.9050, 0.6935)\n centers[20] = (0.1172, 0.8794)\n centers[21] = (0.3315, 0.9017)\n centers[22] = (0.5109, 0.9181)\n centers[23] = (0.6738, 0.9190)\n centers[24] = (0.8611, 0.8918)\n centers[25] = (0.5147, 0.5377)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.0872565960928697 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_128/results/packing_viz.png", + "execution_time_mean": 31.48723436286673, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1fae79eb397d6c43245cb19b2dc6a34cd0dffd72 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..815bc9d39bbadf2e94ed313fda95f5fc1532dda2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_13/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_13/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.853356327835797 + 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} + private: {'reported_sum_of_radii': 1.853356327835797} + visualization_path: + execution_time_mean: 0.002400230150669813 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..1212b38aaceae16a61e3cc98cc7dc9031fc8b6bc --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.853356327835797, + "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 + }, + "private": { + "reported_sum_of_radii": 1.853356327835797 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_13/results/packing_viz.png", + "execution_time_mean": 0.002400230150669813, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ecbe66fd89f61dcb1d4bc0dea8d23fc00a9d5baa Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..51f3a56799fa3af5a0e1823d618212176da804dc --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_130/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_130/results +Run 1/1 completed in 26.45 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.2935521573250055 + public: {'centers_str': ' centers[0] = (0.1683, 0.0619)\n centers[1] = (0.5381, 0.5559)\n centers[2] = (0.3190, 0.1385)\n centers[3] = (0.7163, 0.0842)\n centers[4] = (0.8997, 0.1120)\n centers[5] = (0.1192, 0.2259)\n centers[6] = (0.5285, 0.1241)\n centers[7] = (0.3172, 0.3544)\n centers[8] = (0.4051, 0.0408)\n centers[9] = (0.7275, 0.2528)\n centers[10] = (0.1080, 0.4474)\n centers[11] = (0.5270, 0.3684)\n centers[12] = (0.5376, 0.8235)\n centers[13] = (0.6746, 0.5433)\n centers[14] = (0.8843, 0.6663)\n centers[15] = (0.1215, 0.6761)\n centers[16] = (0.3340, 0.5428)\n centers[17] = (0.3360, 0.7735)\n centers[18] = (0.8560, 0.8899)\n centers[19] = (0.8826, 0.4336)\n centers[20] = (0.1605, 0.8964)\n centers[21] = (0.5053, 0.6628)\n centers[22] = (0.4342, 0.9278)\n centers[23] = (0.6887, 0.9387)\n centers[24] = (0.6729, 0.7691)\n centers[25] = (0.0612, 0.0609)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.2935521573250055} + visualization_path: + execution_time_mean: 26.449987335130572 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..ed71722a898020baebbd3354c17012c4dd5bc6c9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.2935521573250055, + "public": { + "centers_str": " centers[0] = (0.1683, 0.0619)\n centers[1] = (0.5381, 0.5559)\n centers[2] = (0.3190, 0.1385)\n centers[3] = (0.7163, 0.0842)\n centers[4] = (0.8997, 0.1120)\n centers[5] = (0.1192, 0.2259)\n centers[6] = (0.5285, 0.1241)\n centers[7] = (0.3172, 0.3544)\n centers[8] = (0.4051, 0.0408)\n centers[9] = (0.7275, 0.2528)\n centers[10] = (0.1080, 0.4474)\n centers[11] = (0.5270, 0.3684)\n centers[12] = (0.5376, 0.8235)\n centers[13] = (0.6746, 0.5433)\n centers[14] = (0.8843, 0.6663)\n centers[15] = (0.1215, 0.6761)\n centers[16] = (0.3340, 0.5428)\n centers[17] = (0.3360, 0.7735)\n centers[18] = (0.8560, 0.8899)\n centers[19] = (0.8826, 0.4336)\n centers[20] = (0.1605, 0.8964)\n centers[21] = (0.5053, 0.6628)\n centers[22] = (0.4342, 0.9278)\n centers[23] = (0.6887, 0.9387)\n centers[24] = (0.6729, 0.7691)\n centers[25] = (0.0612, 0.0609)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.2935521573250055 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_130/results/packing_viz.png", + "execution_time_mean": 26.449987335130572, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ecfc4e18920bcffd072bfaad3fd473b70c732755 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..b7c841da2d2aed986137fcf6a48a6c18795d36ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/edit.diff @@ -0,0 +1,325 @@ +--- a/original.py ++++ b/original.py +@@ -1,277 +1,300 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + + # compute_max_radii remains unchanged as it's a robust evaluation function. + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + +- for _ in range(500): ++ for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True ++ else: # If both radii are already ~0, ensure they are exactly 0 ++ radii[i] = 0.0 ++ radii[j] = 0.0 ++ changes_made = True + if not changes_made: + break + return radii + + class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) +- mask = distances > 1e-9 ++ mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) +- push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) +- ++ # Apply push only to points not exactly at the void center + if np.any(mask): ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ ++ # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- initial_centers[25] = void_center ++ initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + +- def _force_directed_relaxation(self, iters, step_size, repulsion_strength, ++ def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): ++ forces = np.zeros_like(self.centers) ++ + # Vectorized Circle-Circle Repulsion +- diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] +- dists = np.linalg.norm(diff, axis=2) +- +- mask = (dists > 1e-9) & (dists < repulsion_threshold) ++ diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] # (N, N, 2) ++ dists = np.linalg.norm(diff, axis=2) # (N, N) ++ ++ # Mask out self-interaction by setting diagonal distances to a very large value ++ np.fill_diagonal(dists, np.inf) ++ ++ # Repulsion mask for pairs that are close enough to interact ++ repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + +- force_scalar = np.zeros_like(dists) +- force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] +- +- # Use np.divide with where clause to handle potential division by zero for diff/dists +- force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +- forces = np.sum(force_vectors, axis=1) ++ # Compute force magnitudes for interacting pairs ++ force_magnitudes = np.zeros_like(dists) ++ force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] ++ ++ # Compute force vectors F_ij (force on i from j) ++ # F_ij direction is (centers[i] - centers[j]) / dists[i,j] ++ # Store unit vectors: normalized_diff[i,j] = (centers[i] - centers[j]) / dists[i,j] ++ normalized_diff = np.zeros_like(diff) ++ # Avoid division by zero where dists might be zero or inf (already handled diag to inf) ++ # The where clause ensures division only happens for valid non-zero distances. ++ # This covers the repulsion_mask values which are > 1e-9. ++ normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ ++ # Sum force_magnitudes[i,j] * normalized_diff[i,j] over j for each i ++ # This correctly sums F_ij (force exerted by j on i) for all j!=i ++ forces_repulsion = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) ++ forces += forces_repulsion + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + +- def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, ++ def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + +- current_centers = self.centers.copy() ++ current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + for iteration in range(total_iterations): +- # Logarithmic decay for temperature and perturbation strength ++ # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos +- self._force_directed_relaxation( ++ self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization +- self._simulated_annealing_local_search( ++ self._simulated_annealing_search( + total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. +- self._force_directed_relaxation( ++ self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/main.py new file mode 100644 index 0000000000000000000000000000000000000000..46ec3682ad21ce0301f80d87e3f73566aade879b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/main.py @@ -0,0 +1,300 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] # (N, N, 2) + dists = np.linalg.norm(diff, axis=2) # (N, N) + + # Mask out self-interaction by setting diagonal distances to a very large value + np.fill_diagonal(dists, np.inf) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors F_ij (force on i from j) + # F_ij direction is (centers[i] - centers[j]) / dists[i,j] + # Store unit vectors: normalized_diff[i,j] = (centers[i] - centers[j]) / dists[i,j] + normalized_diff = np.zeros_like(diff) + # Avoid division by zero where dists might be zero or inf (already handled diag to inf) + # The where clause ensures division only happens for valid non-zero distances. + # This covers the repulsion_mask values which are > 1e-9. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # Sum force_magnitudes[i,j] * normalized_diff[i,j] over j for each i + # This correctly sums F_ij (force exerted by j on i) for all j!=i + forces_repulsion = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + forces += forces_repulsion + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( + total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/original.py new file mode 100644 index 0000000000000000000000000000000000000000..31ab06b5a7bdf04fc36c0f8c7ec5dcce4da7050c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/original.py @@ -0,0 +1,277 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Use np.divide with where clause to handle potential division by zero for diff/dists + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = self.centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_local_search( + total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..3f763e1de624affba7be7a07a400e36bf9383475 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_131/main.py:120: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..ab5f05cb316aaf3f8fe69c8f6e000e67bdad0305 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_131/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_131/results +Run 1/1 completed in 31.82 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.126925945533294 + public: {'centers_str': ' centers[0] = (0.0980, 0.0980)\n centers[1] = (0.2812, 0.0856)\n centers[2] = (0.4731, 0.1043)\n centers[3] = (0.6852, 0.1020)\n centers[4] = (0.8949, 0.1048)\n centers[5] = (0.0830, 0.2784)\n centers[6] = (0.3095, 0.2531)\n centers[7] = (0.5338, 0.2460)\n centers[8] = (0.7376, 0.2310)\n centers[9] = (0.9109, 0.2981)\n centers[10] = (0.0675, 0.5307)\n centers[11] = (0.1583, 0.3984)\n centers[12] = (0.4605, 0.6217)\n centers[13] = (0.7809, 0.6300)\n centers[14] = (0.9196, 0.4674)\n centers[15] = (0.0951, 0.6925)\n centers[16] = (0.2894, 0.6827)\n centers[17] = (0.4918, 0.7355)\n centers[18] = (0.6961, 0.7273)\n centers[19] = (0.9037, 0.7045)\n centers[20] = (0.1048, 0.8922)\n centers[21] = (0.3197, 0.8900)\n centers[22] = (0.5186, 0.9117)\n centers[23] = (0.7023, 0.9044)\n centers[24] = (0.8975, 0.9003)\n centers[25] = (0.6087, 0.4783)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.126925945533294} + visualization_path: + execution_time_mean: 31.818676526192576 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..4c37221e6f6aa452acddcdb2e2a24f283435e400 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.126925945533294, + "public": { + "centers_str": " centers[0] = (0.0980, 0.0980)\n centers[1] = (0.2812, 0.0856)\n centers[2] = (0.4731, 0.1043)\n centers[3] = (0.6852, 0.1020)\n centers[4] = (0.8949, 0.1048)\n centers[5] = (0.0830, 0.2784)\n centers[6] = (0.3095, 0.2531)\n centers[7] = (0.5338, 0.2460)\n centers[8] = (0.7376, 0.2310)\n centers[9] = (0.9109, 0.2981)\n centers[10] = (0.0675, 0.5307)\n centers[11] = (0.1583, 0.3984)\n centers[12] = (0.4605, 0.6217)\n centers[13] = (0.7809, 0.6300)\n centers[14] = (0.9196, 0.4674)\n centers[15] = (0.0951, 0.6925)\n centers[16] = (0.2894, 0.6827)\n centers[17] = (0.4918, 0.7355)\n centers[18] = (0.6961, 0.7273)\n centers[19] = (0.9037, 0.7045)\n centers[20] = (0.1048, 0.8922)\n centers[21] = (0.3197, 0.8900)\n centers[22] = (0.5186, 0.9117)\n centers[23] = (0.7023, 0.9044)\n centers[24] = (0.8975, 0.9003)\n centers[25] = (0.6087, 0.4783)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.126925945533294 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_131/results/packing_viz.png", + "execution_time_mean": 31.818676526192576, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..ebdaa748bdbee020e2facea6f88ab80c2fb2c324 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_131/rewrite.txt @@ -0,0 +1,291 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] # (N, N, 2) + dists = np.linalg.norm(diff, axis=2) # (N, N) + + # Mask out self-interaction by setting diagonal distances to a very large value + np.fill_diagonal(dists, np.inf) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors F_ij (force on i from j) + # F_ij direction is (centers[i] - centers[j]) / dists[i,j] + # Store unit vectors: normalized_diff[i,j] = (centers[i] - centers[j]) / dists[i,j] + normalized_diff = np.zeros_like(diff) + # Avoid division by zero where dists might be zero or inf (already handled diag to inf) + # The where clause ensures division only happens for valid non-zero distances. + # This covers the repulsion_mask values which are > 1e-9. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # Sum force_magnitudes[i,j] * normalized_diff[i,j] over j for each i + # This correctly sums F_ij (force exerted by j on i) for all j!=i + forces_repulsion = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + forces += forces_repulsion + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( + total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8483b471f1ef63b3f9a864840d47e46f85a02443 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..bcdb3214c4d0ea834a5b9488dc6928f01f4c6605 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_132/main.py:111: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + unit_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..d862e5f6fb045e951bf1906de8c27948752ee73f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_132/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_132/results +Run 1/1 completed in 47.57 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9825782240400591 + public: {'centers_str': ' centers[0] = (0.0937, 0.0980)\n centers[1] = (0.2728, 0.0727)\n centers[2] = (0.5272, 0.0727)\n centers[3] = (0.7062, 0.0980)\n centers[4] = (0.9002, 0.1000)\n centers[5] = (0.0937, 0.3020)\n centers[6] = (0.2728, 0.3272)\n centers[7] = (0.5272, 0.3272)\n centers[8] = (0.7062, 0.3020)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0992, 0.5008)\n centers[11] = (0.2980, 0.5062)\n centers[12] = (0.5020, 0.5062)\n centers[13] = (0.7008, 0.5008)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7002)\n centers[17] = (0.5000, 0.7002)\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.4000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9825782240400591} + visualization_path: + execution_time_mean: 47.572265001013875 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..1e9f8473ea2cc81370f4b7dbf432109b8ac72e9e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9825782240400591, + "public": { + "centers_str": " centers[0] = (0.0937, 0.0980)\n centers[1] = (0.2728, 0.0727)\n centers[2] = (0.5272, 0.0727)\n centers[3] = (0.7062, 0.0980)\n centers[4] = (0.9002, 0.1000)\n centers[5] = (0.0937, 0.3020)\n centers[6] = (0.2728, 0.3272)\n centers[7] = (0.5272, 0.3272)\n centers[8] = (0.7062, 0.3020)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0992, 0.5008)\n centers[11] = (0.2980, 0.5062)\n centers[12] = (0.5020, 0.5062)\n centers[13] = (0.7008, 0.5008)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7002)\n centers[17] = (0.5000, 0.7002)\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.4000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9825782240400591 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_132/results/packing_viz.png", + "execution_time_mean": 47.572265001013875, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..efceb07ced254031312871bbc0e566da07b8b848 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..c08818792b9be1bf0b0f190752370e1dae273e5f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/edit.diff @@ -0,0 +1,475 @@ +--- a/original.py ++++ b/original.py +@@ -1,200 +1,315 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" ++"""Constructor-based circle packing for n=26 circles using Hybrid Simulated Annealing with Localized Force-Directed Relaxation""" + + import numpy as np + ++def compute_max_radii(centers): ++ """ ++ Compute the maximum possible radii for each circle position ++ such that they don't overlap and stay within the unit square. This is ++ an iterative version that converges to a stable solution. ++ ++ Args: ++ centers: np.array of shape (n, 2) with (x, y) coordinates ++ ++ Returns: ++ np.array of shape (n) with radius of each circle ++ """ ++ n = centers.shape[0] ++ ++ # Initialize radii based on distance to the square's boundaries (vectorized). ++ radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) ++ ++ # Iteratively resolve overlaps between circles until no more changes occur. ++ # A high number of iterations ensures convergence for complex arrangements. ++ for _ in range(500): # Increased iterations for more thorough convergence ++ changes_made = False ++ ++ for i in range(n): ++ for j in range(i + 1, n): ++ dist = np.linalg.norm(centers[i] - centers[j]) ++ ++ # If they overlap (with a small tolerance for floating point math) ++ if radii[i] + radii[j] > dist + 1e-12: ++ sum_r = radii[i] + radii[j] ++ if sum_r > 1e-12: # Avoid division by zero ++ # Scale both radii down proportionally to resolve the overlap. ++ scale = dist / sum_r ++ ri_new, rj_new = radii[i] * scale, radii[j] * scale ++ ++ # Check for significant change to set the flag ++ if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: ++ radii[i], radii[j] = ri_new, rj_new ++ changes_made = True ++ else: # If both radii are already ~0, ensure they are exactly 0 ++ if radii[i] > 1e-12 or radii[j] > 1e-12: # Only if they weren't already zero ++ radii[i] = 0 ++ radii[j] = 0 ++ changes_made = True # A change has occurred ++ ++ # If no significant changes were made in a full pass, the packing is stable. ++ if not changes_made: ++ break ++ ++ return radii ++ ++def _apply_force_directed_relaxation(centers, n, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin, affected_indices=None): ++ """ ++ Applies a force-directed relaxation algorithm to a set of circle centers. ++ Circles repel each other and are repelled by boundaries. ++ Can be applied to a subset of circles (affected_indices). ++ """ ++ current_centers = centers.copy() ++ ++ # Determine which circles are allowed to move. If None, all circles move. ++ if affected_indices is None: ++ indices_to_move = np.arange(n) ++ else: ++ indices_to_move = np.array(affected_indices) ++ ++ for _ in range(iterations): ++ # Calculate forces for ALL circles, as fixed circles still exert repulsion. ++ # However, only the positions of 'indices_to_move' will be updated. ++ total_forces = np.zeros_like(current_centers) ++ ++ # Circle-circle repulsion ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = current_centers[i] - current_centers[j] ++ dist = np.linalg.norm(vec) ++ ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ total_forces[i] += force_vec ++ total_forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n): ++ x, y = current_centers[i] ++ if x < boundary_margin: total_forces[i, 0] += boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: total_forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: total_forces[i, 1] += boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: total_forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) ++ ++ # Apply forces only to the circles specified in affected_indices ++ current_centers[indices_to_move] += step_size * total_forces[indices_to_move] ++ current_centers[indices_to_move] = np.clip(current_centers[indices_to_move], 0.0, 1.0) # Keep centers within bounds ++ ++ return current_centers ++ + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles by combining a +- vectorized Gaussian-deformed grid initialization with a three-stage adaptive +- force-directed relaxation (Aggressive Exploration, Gentle Refinement, and +- Ultra-fine Annealing with adaptive boundaries) to optimize the final positions. ++ Constructs a high-density arrangement of 26 circles using a hybrid approach: ++ 1. Asymmetric Gaussian-deformed grid initialization. ++ 2. Simulated Annealing with localized Force-Directed Relaxation perturbations ++ for global exploration and efficient local moves. ++ 3. Global multi-stage Force-Directed Refinement for deterministic fine-tuning. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 +- centers = np.zeros((n, 2)) +- +- # 1. Initial Grid for 25 circles: Start with a 5x5 grid. ++ ++ # 1. Initialization: Asymmetric Gaussian-deformed grid + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Place the 26th circle in an asymmetric void and deform the grid. +- # This is a crossover from the 'inspiration' program for efficiency. + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + +- # Using a vectorized approach for displacement calculation + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + +- deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- +- centers[:25] = deformed_centers_25 +- centers[25] = void_center +- centers = np.clip(centers, 0.0, 1.0) +- +- # 3. Three-Stage Adaptive Force-Directed Relaxation +- # This hybrid approach uses a strong shake, then progressively gentler settling +- # with adaptive boundary margins for optimal packing. +- +- # Stage 1: High-Energy Exploration ("Shaking") +- # Using strong forces from the 'current' program to break symmetry effectively. +- exploration_iters = 300 +- exploration_step_size = 0.003 +- exploration_repulsion_strength = 0.025 # Stronger shake +- exploration_boundary_strength = 0.1 +- exploration_repulsion_threshold = 0.20 +- exploration_boundary_margin = 0.04 # Standard wide margin +- +- for _ in range(exploration_iters): +- forces = np.zeros_like(centers) +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < exploration_repulsion_threshold: +- force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist +- force_vec = force_mag * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- for i in range(n): +- x, y = centers[i] +- if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) +- if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) +- if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) +- if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) +- centers += exploration_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- +- +- # Stage 2: Low-Energy Refinement ("Settling") +- # Using gentler forces from the 'inspiration' program with a tighter boundary. +- refinement_iters = 500 +- refinement_step_size = 0.0008 # Inspiration's step +- refinement_repulsion_strength = 0.005 # Inspiration's gentle force +- refinement_boundary_strength = 0.025 +- refinement_repulsion_threshold = 0.18 # Inspiration's tighter threshold +- refinement_boundary_margin = 0.02 # Adaptive margin +- +- for _ in range(refinement_iters): +- forces = np.zeros_like(centers) +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < refinement_repulsion_threshold: +- force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist +- force_vec = force_mag * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- for i in range(n): +- x, y = centers[i] +- if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) +- if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) +- if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) +- if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) +- centers += refinement_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- +- # Stage 3: Ultra-Low-Energy Annealing ("Polishing") +- # Using very weak forces from 'inspiration' and a very tight boundary margin. +- annealing_iters = 800 +- annealing_step_size = 0.0002 +- annealing_repulsion_strength = 0.001 # Ultra-gentle force +- annealing_boundary_strength = 0.005 +- annealing_repulsion_threshold = 0.175 # Very tight threshold +- annealing_boundary_margin = 0.01 # Smallest margin to hug the edges +- +- for _ in range(annealing_iters): +- forces = np.zeros_like(centers) +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < annealing_repulsion_threshold: +- force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist +- force_vec = force_mag * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- for i in range(n): +- x, y = centers[i] +- if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) +- if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) +- if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) +- if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) +- centers += annealing_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- +- # 4. Compute maximum valid radii for the final configuration. +- radii = compute_max_radii(centers) +- return centers, radii +- +- +-def compute_max_radii(centers): +- """ +- Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This version +- is from the 'inspiration' program, using vectorized initialization and +- iterative conflict resolution until convergence. +- +- Args: +- centers: np.array of shape (n, 2) with (x, y) coordinates +- +- Returns: +- np.array of shape (n) with radius of each circle +- """ +- n = centers.shape[0] +- +- # First, limit by distance to square borders (vectorized for efficiency) +- radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) +- +- # Iteratively limit by distance to other circles, allowing constraints to propagate +- for _ in range(300): # Iterate to ensure convergence +- changes_made = False +- for i in range(n): +- for j in range(i + 1, n): +- dist = np.linalg.norm(centers[i] - centers[j]) +- +- # If current radii cause overlap +- if radii[i] + radii[j] > dist: +- sum_r = radii[i] + radii[j] +- if sum_r > 1e-9: # Avoid division by zero +- # Scale both radii proportionally to resolve overlap +- scale = dist / sum_r +- ri_new = radii[i] * scale +- rj_new = radii[j] * scale +- +- # Check for significant change to set the flag +- if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: +- radii[i] = ri_new +- radii[j] = rj_new +- changes_made = True +- if not changes_made: +- break # Exit early if the configuration is stable +- +- return radii ++ initial_centers = np.zeros((n, 2)) ++ initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ initial_centers[25] = void_center ++ initial_centers = np.clip(initial_centers, 0.0, 1.0) ++ ++ # Initial pre-optimization: A short, mild global FDR to stabilize the grid ++ pre_optimized_centers = _apply_force_directed_relaxation( ++ initial_centers.copy(), ++ n=n, ++ iterations=100, ++ step_size=0.001, ++ repulsion_strength=0.01, ++ repulsion_threshold=0.18, ++ boundary_strength=0.05, ++ boundary_margin=0.03, ++ affected_indices=None # All circles move ++ ) ++ ++ current_centers = pre_optimized_centers.copy() ++ current_radii = compute_max_radii(current_centers) ++ current_sum_radii = np.sum(current_radii) ++ ++ best_centers = current_centers.copy() ++ best_radii = current_radii.copy() ++ best_sum_radii = current_sum_radii ++ ++ # 2. Simulated Annealing with Localized Force-Directed Perturbations ++ total_sa_iterations = 15000 # Increased iterations for SA ++ T_initial = 0.15 # Slightly higher initial temperature for broader exploration ++ T_final = 1e-7 # Very low final temperature ++ ++ # Parameters for localized FDR during SA ++ local_fdr_iterations = 15 # A few more internal FDR steps for better local optimization ++ local_fdr_repulsion_strength = 0.02 ++ local_fdr_boundary_strength = 0.05 ++ ++ # Adaptive number of neighbors for localized FDR ++ num_neighbors_initial = 3 # Main circle + 3 closest neighbors = 4 circles ++ num_neighbors_final = 1 # Main circle + 1 closest neighbor = 2 circles ++ ++ # Adaptive global perturbation strength (influences local FDR parameters) ++ initial_global_perturb_strength = 0.04 # Slightly increased for initial SA exploration ++ final_global_perturb_strength = 0.0002 # Very small for fine-tuning towards the end ++ ++ for iteration in range(total_sa_iterations): ++ # Decay global perturbation strength and temperature ++ global_perturb_strength = initial_global_perturb_strength * (1 - iteration / total_sa_iterations) + final_global_perturb_strength * (iteration / total_sa_iterations) ++ temperature = T_initial * (T_final / T_initial)**(iteration / total_sa_iterations) ++ ++ candidate_centers = current_centers.copy() ++ ++ # Select a circle to perturb using adaptive criteria (smaller radii more likely) ++ inverse_radii = 1 / (current_radii + 1e-8) ++ selection_probs = inverse_radii / np.sum(inverse_radii) ++ main_circle_idx = np.random.choice(n, p=selection_probs) ++ ++ # Determine the number of neighbors for localized FDR ++ current_num_neighbors = round(num_neighbors_initial * (1 - iteration / total_sa_iterations) + num_neighbors_final * (iteration / total_sa_iterations)) ++ ++ # Identify the group of circles for localized FDR (main_circle_idx + its closest neighbors) ++ distances_from_main = np.linalg.norm(current_centers - current_centers[main_circle_idx], axis=1) ++ # Sort distances and pick closest (excluding itself) ++ closest_indices = np.argsort(distances_from_main) ++ ++ affected_indices = [main_circle_idx] ++ count = 0 ++ for idx in closest_indices: ++ if idx == main_circle_idx: ++ continue ++ if count < current_num_neighbors: ++ affected_indices.append(idx) ++ count += 1 ++ else: ++ break ++ affected_indices = np.array(affected_indices) ++ ++ # Adapt local FDR step_size and thresholds based on SA's global_perturb_strength ++ # Larger global_perturb_strength means larger steps and broader interaction range for local FDR ++ local_fdr_step_size = global_perturb_strength * 0.1 # Scale step_size by global perturb ++ ++ # Repulsion threshold and boundary margin for local FDR also adapt ++ # They will be larger (more interaction) at the beginning of SA and smaller (finer interaction) towards the end ++ current_local_fdr_repulsion_threshold = 0.15 + global_perturb_strength * 2 ++ current_local_fdr_boundary_margin = 0.02 + global_perturb_strength * 0.5 ++ ++ ++ # Apply localized Force-Directed Relaxation to the selected group ++ candidate_centers = _apply_force_directed_relaxation( ++ candidate_centers, ++ n=n, ++ iterations=local_fdr_iterations, ++ step_size=local_fdr_step_size, ++ repulsion_strength=local_fdr_repulsion_strength, ++ repulsion_threshold=current_local_fdr_repulsion_threshold, ++ boundary_strength=local_fdr_boundary_strength, ++ boundary_margin=current_local_fdr_boundary_margin, ++ affected_indices=affected_indices ++ ) ++ ++ candidate_radii = compute_max_radii(candidate_centers) ++ candidate_sum_radii = np.sum(candidate_radii) ++ ++ # Simulated Annealing acceptance criteria ++ if candidate_sum_radii > current_sum_radii: ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers.copy() ++ current_radii = candidate_radii.copy() ++ else: ++ delta = candidate_sum_radii - current_sum_radii ++ acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 ++ if np.random.rand() < acceptance_prob: ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers.copy() ++ current_radii = candidate_radii.copy() ++ ++ if current_sum_radii > best_sum_radii: ++ best_sum_radii = current_sum_radii ++ best_centers = current_centers.copy() ++ best_radii = current_radii.copy() ++ # print(f"SA Iter {iteration}: New best sum of radii: {best_sum_radii:.4f}") ++ ++ # 3. Global Multi-stage Force-Directed Refinement (Deterministic Fine-Tuning) ++ # This phase polishes the arrangement found by SA, which serves as an excellent starting point. ++ ++ # Stage 1: Initial broad refinement ++ refined_centers = _apply_force_directed_relaxation( ++ best_centers.copy(), ++ n=n, ++ iterations=400, # Increased iterations ++ step_size=0.0012, # Slightly more aggressive step ++ repulsion_strength=0.009, ++ repulsion_threshold=0.185, # Broader repulsion ++ boundary_strength=0.04, ++ boundary_margin=0.035 ++ ) ++ ++ # Stage 2: Fine-tuning ++ refined_centers = _apply_force_directed_relaxation( ++ refined_centers, ++ n=n, ++ iterations=600, # Increased iterations ++ step_size=0.0006, ++ repulsion_strength=0.004, ++ repulsion_threshold=0.178, # Tighter repulsion ++ boundary_strength=0.02, ++ boundary_margin=0.02 ++ ) ++ ++ # Stage 3: Ultra-fine polish (gentle, long-duration) ++ refined_centers = _apply_force_directed_relaxation( ++ refined_centers, ++ n=n, ++ iterations=1000, # More iterations for final polish ++ step_size=0.0001, ++ repulsion_strength=0.001, ++ repulsion_threshold=0.17, # Very tight repulsion ++ boundary_strength=0.005, ++ boundary_margin=0.005 # Hugging edges ++ ) ++ ++ final_radii = compute_max_radii(refined_centers) ++ final_sum_radii = np.sum(final_radii) ++ ++ # Return the best from SA (which might be better if refinement overshot) ++ # or the result after final refinement, whichever yielded a higher sum. ++ if final_sum_radii > best_sum_radii: ++ return refined_centers, final_radii ++ else: ++ return best_centers, best_radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/main.py new file mode 100644 index 0000000000000000000000000000000000000000..a2285aeb039ffbfe0752cd4cf73b983df748ec4e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/main.py @@ -0,0 +1,315 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using Hybrid Simulated Annealing with Localized Force-Directed Relaxation""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + if radii[i] > 1e-12 or radii[j] > 1e-12: # Only if they weren't already zero + radii[i] = 0 + radii[j] = 0 + changes_made = True # A change has occurred + + # If no significant changes were made in a full pass, the packing is stable. + if not changes_made: + break + + return radii + +def _apply_force_directed_relaxation(centers, n, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin, affected_indices=None): + """ + Applies a force-directed relaxation algorithm to a set of circle centers. + Circles repel each other and are repelled by boundaries. + Can be applied to a subset of circles (affected_indices). + """ + current_centers = centers.copy() + + # Determine which circles are allowed to move. If None, all circles move. + if affected_indices is None: + indices_to_move = np.arange(n) + else: + indices_to_move = np.array(affected_indices) + + for _ in range(iterations): + # Calculate forces for ALL circles, as fixed circles still exert repulsion. + # However, only the positions of 'indices_to_move' will be updated. + total_forces = np.zeros_like(current_centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = current_centers[i] - current_centers[j] + dist = np.linalg.norm(vec) + + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + total_forces[i] += force_vec + total_forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = current_centers[i] + if x < boundary_margin: total_forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: total_forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: total_forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: total_forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + # Apply forces only to the circles specified in affected_indices + current_centers[indices_to_move] += step_size * total_forces[indices_to_move] + current_centers[indices_to_move] = np.clip(current_centers[indices_to_move], 0.0, 1.0) # Keep centers within bounds + + return current_centers + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a hybrid approach: + 1. Asymmetric Gaussian-deformed grid initialization. + 2. Simulated Annealing with localized Force-Directed Relaxation perturbations + for global exploration and efficient local moves. + 3. Global multi-stage Force-Directed Refinement for deterministic fine-tuning. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Initialization: Asymmetric Gaussian-deformed grid + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + initial_centers = np.clip(initial_centers, 0.0, 1.0) + + # Initial pre-optimization: A short, mild global FDR to stabilize the grid + pre_optimized_centers = _apply_force_directed_relaxation( + initial_centers.copy(), + n=n, + iterations=100, + step_size=0.001, + repulsion_strength=0.01, + repulsion_threshold=0.18, + boundary_strength=0.05, + boundary_margin=0.03, + affected_indices=None # All circles move + ) + + current_centers = pre_optimized_centers.copy() + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_radii = current_radii.copy() + best_sum_radii = current_sum_radii + + # 2. Simulated Annealing with Localized Force-Directed Perturbations + total_sa_iterations = 15000 # Increased iterations for SA + T_initial = 0.15 # Slightly higher initial temperature for broader exploration + T_final = 1e-7 # Very low final temperature + + # Parameters for localized FDR during SA + local_fdr_iterations = 15 # A few more internal FDR steps for better local optimization + local_fdr_repulsion_strength = 0.02 + local_fdr_boundary_strength = 0.05 + + # Adaptive number of neighbors for localized FDR + num_neighbors_initial = 3 # Main circle + 3 closest neighbors = 4 circles + num_neighbors_final = 1 # Main circle + 1 closest neighbor = 2 circles + + # Adaptive global perturbation strength (influences local FDR parameters) + initial_global_perturb_strength = 0.04 # Slightly increased for initial SA exploration + final_global_perturb_strength = 0.0002 # Very small for fine-tuning towards the end + + for iteration in range(total_sa_iterations): + # Decay global perturbation strength and temperature + global_perturb_strength = initial_global_perturb_strength * (1 - iteration / total_sa_iterations) + final_global_perturb_strength * (iteration / total_sa_iterations) + temperature = T_initial * (T_final / T_initial)**(iteration / total_sa_iterations) + + candidate_centers = current_centers.copy() + + # Select a circle to perturb using adaptive criteria (smaller radii more likely) + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + main_circle_idx = np.random.choice(n, p=selection_probs) + + # Determine the number of neighbors for localized FDR + current_num_neighbors = round(num_neighbors_initial * (1 - iteration / total_sa_iterations) + num_neighbors_final * (iteration / total_sa_iterations)) + + # Identify the group of circles for localized FDR (main_circle_idx + its closest neighbors) + distances_from_main = np.linalg.norm(current_centers - current_centers[main_circle_idx], axis=1) + # Sort distances and pick closest (excluding itself) + closest_indices = np.argsort(distances_from_main) + + affected_indices = [main_circle_idx] + count = 0 + for idx in closest_indices: + if idx == main_circle_idx: + continue + if count < current_num_neighbors: + affected_indices.append(idx) + count += 1 + else: + break + affected_indices = np.array(affected_indices) + + # Adapt local FDR step_size and thresholds based on SA's global_perturb_strength + # Larger global_perturb_strength means larger steps and broader interaction range for local FDR + local_fdr_step_size = global_perturb_strength * 0.1 # Scale step_size by global perturb + + # Repulsion threshold and boundary margin for local FDR also adapt + # They will be larger (more interaction) at the beginning of SA and smaller (finer interaction) towards the end + current_local_fdr_repulsion_threshold = 0.15 + global_perturb_strength * 2 + current_local_fdr_boundary_margin = 0.02 + global_perturb_strength * 0.5 + + + # Apply localized Force-Directed Relaxation to the selected group + candidate_centers = _apply_force_directed_relaxation( + candidate_centers, + n=n, + iterations=local_fdr_iterations, + step_size=local_fdr_step_size, + repulsion_strength=local_fdr_repulsion_strength, + repulsion_threshold=current_local_fdr_repulsion_threshold, + boundary_strength=local_fdr_boundary_strength, + boundary_margin=current_local_fdr_boundary_margin, + affected_indices=affected_indices + ) + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + else: + delta = candidate_sum_radii - current_sum_radii + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + # print(f"SA Iter {iteration}: New best sum of radii: {best_sum_radii:.4f}") + + # 3. Global Multi-stage Force-Directed Refinement (Deterministic Fine-Tuning) + # This phase polishes the arrangement found by SA, which serves as an excellent starting point. + + # Stage 1: Initial broad refinement + refined_centers = _apply_force_directed_relaxation( + best_centers.copy(), + n=n, + iterations=400, # Increased iterations + step_size=0.0012, # Slightly more aggressive step + repulsion_strength=0.009, + repulsion_threshold=0.185, # Broader repulsion + boundary_strength=0.04, + boundary_margin=0.035 + ) + + # Stage 2: Fine-tuning + refined_centers = _apply_force_directed_relaxation( + refined_centers, + n=n, + iterations=600, # Increased iterations + step_size=0.0006, + repulsion_strength=0.004, + repulsion_threshold=0.178, # Tighter repulsion + boundary_strength=0.02, + boundary_margin=0.02 + ) + + # Stage 3: Ultra-fine polish (gentle, long-duration) + refined_centers = _apply_force_directed_relaxation( + refined_centers, + n=n, + iterations=1000, # More iterations for final polish + step_size=0.0001, + repulsion_strength=0.001, + repulsion_threshold=0.17, # Very tight repulsion + boundary_strength=0.005, + boundary_margin=0.005 # Hugging edges + ) + + final_radii = compute_max_radii(refined_centers) + final_sum_radii = np.sum(final_radii) + + # Return the best from SA (which might be better if refinement overshot) + # or the result after final refinement, whichever yielded a higher sum. + if final_sum_radii > best_sum_radii: + return refined_centers, final_radii + else: + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/original.py new file mode 100644 index 0000000000000000000000000000000000000000..9e82e59cee450857f1d06f820737257c42c57cc9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/original.py @@ -0,0 +1,200 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by combining a + vectorized Gaussian-deformed grid initialization with a three-stage adaptive + force-directed relaxation (Aggressive Exploration, Gentle Refinement, and + Ultra-fine Annealing with adaptive boundaries) to optimize the final positions. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in an asymmetric void and deform the grid. + # This is a crossover from the 'inspiration' program for efficiency. + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + # Using a vectorized approach for displacement calculation + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 3. Three-Stage Adaptive Force-Directed Relaxation + # This hybrid approach uses a strong shake, then progressively gentler settling + # with adaptive boundary margins for optimal packing. + + # Stage 1: High-Energy Exploration ("Shaking") + # Using strong forces from the 'current' program to break symmetry effectively. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 # Stronger shake + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + exploration_boundary_margin = 0.04 # Standard wide margin + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + + # Stage 2: Low-Energy Refinement ("Settling") + # Using gentler forces from the 'inspiration' program with a tighter boundary. + refinement_iters = 500 + refinement_step_size = 0.0008 # Inspiration's step + refinement_repulsion_strength = 0.005 # Inspiration's gentle force + refinement_boundary_strength = 0.025 + refinement_repulsion_threshold = 0.18 # Inspiration's tighter threshold + refinement_boundary_margin = 0.02 # Adaptive margin + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # Using very weak forces from 'inspiration' and a very tight boundary margin. + annealing_iters = 800 + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 # Ultra-gentle force + annealing_boundary_strength = 0.005 + annealing_repulsion_threshold = 0.175 # Very tight threshold + annealing_boundary_margin = 0.01 # Smallest margin to hug the edges + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 4. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + is from the 'inspiration' program, using vectorized initialization and + iterative conflict resolution until convergence. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..ecad0ef2582d0feb696224789b3055a803ea4e73 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_133/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_133/results +Run 1/1 completed in 272.07 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9826667657952903 + public: {'centers_str': ' centers[0] = (0.0938, 0.0979)\n centers[1] = (0.2728, 0.0728)\n centers[2] = (0.5272, 0.0728)\n centers[3] = (0.7062, 0.0979)\n centers[4] = (0.9002, 0.1000)\n centers[5] = (0.0938, 0.3021)\n centers[6] = (0.2728, 0.3272)\n centers[7] = (0.5272, 0.3272)\n centers[8] = (0.7062, 0.3021)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0992, 0.5008)\n centers[11] = (0.2979, 0.5062)\n centers[12] = (0.5021, 0.5062)\n centers[13] = (0.7008, 0.5008)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7002)\n centers[17] = (0.5000, 0.7002)\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.4000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9826667657952903} + visualization_path: + execution_time_mean: 272.07197589520365 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..1f5c3875b696f777fc7c56ea2f20a53538ff877c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9826667657952903, + "public": { + "centers_str": " centers[0] = (0.0938, 0.0979)\n centers[1] = (0.2728, 0.0728)\n centers[2] = (0.5272, 0.0728)\n centers[3] = (0.7062, 0.0979)\n centers[4] = (0.9002, 0.1000)\n centers[5] = (0.0938, 0.3021)\n centers[6] = (0.2728, 0.3272)\n centers[7] = (0.5272, 0.3272)\n centers[8] = (0.7062, 0.3021)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0992, 0.5008)\n centers[11] = (0.2979, 0.5062)\n centers[12] = (0.5021, 0.5062)\n centers[13] = (0.7008, 0.5008)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7002)\n centers[17] = (0.5000, 0.7002)\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.4000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9826667657952903 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_133/results/packing_viz.png", + "execution_time_mean": 272.07197589520365, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..937c87e69f21214c88112712cbf89ab882ad7754 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_133/rewrite.txt @@ -0,0 +1,305 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using Hybrid Simulated Annealing with Localized Force-Directed Relaxation""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + if radii[i] > 1e-12 or radii[j] > 1e-12: # Only if they weren't already zero + radii[i] = 0 + radii[j] = 0 + changes_made = True # A change has occurred + + # If no significant changes were made in a full pass, the packing is stable. + if not changes_made: + break + + return radii + +def _apply_force_directed_relaxation(centers, n, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin, affected_indices=None): + """ + Applies a force-directed relaxation algorithm to a set of circle centers. + Circles repel each other and are repelled by boundaries. + Can be applied to a subset of circles (affected_indices). + """ + current_centers = centers.copy() + + # Determine which circles are allowed to move. If None, all circles move. + if affected_indices is None: + indices_to_move = np.arange(n) + else: + indices_to_move = np.array(affected_indices) + + for _ in range(iterations): + # Calculate forces for ALL circles, as fixed circles still exert repulsion. + # However, only the positions of 'indices_to_move' will be updated. + total_forces = np.zeros_like(current_centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = current_centers[i] - current_centers[j] + dist = np.linalg.norm(vec) + + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + total_forces[i] += force_vec + total_forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = current_centers[i] + if x < boundary_margin: total_forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: total_forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: total_forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: total_forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + # Apply forces only to the circles specified in affected_indices + current_centers[indices_to_move] += step_size * total_forces[indices_to_move] + current_centers[indices_to_move] = np.clip(current_centers[indices_to_move], 0.0, 1.0) # Keep centers within bounds + + return current_centers + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a hybrid approach: + 1. Asymmetric Gaussian-deformed grid initialization. + 2. Simulated Annealing with localized Force-Directed Relaxation perturbations + for global exploration and efficient local moves. + 3. Global multi-stage Force-Directed Refinement for deterministic fine-tuning. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Initialization: Asymmetric Gaussian-deformed grid + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + initial_centers = np.clip(initial_centers, 0.0, 1.0) + + # Initial pre-optimization: A short, mild global FDR to stabilize the grid + pre_optimized_centers = _apply_force_directed_relaxation( + initial_centers.copy(), + n=n, + iterations=100, + step_size=0.001, + repulsion_strength=0.01, + repulsion_threshold=0.18, + boundary_strength=0.05, + boundary_margin=0.03, + affected_indices=None # All circles move + ) + + current_centers = pre_optimized_centers.copy() + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_radii = current_radii.copy() + best_sum_radii = current_sum_radii + + # 2. Simulated Annealing with Localized Force-Directed Perturbations + total_sa_iterations = 15000 # Increased iterations for SA + T_initial = 0.15 # Slightly higher initial temperature for broader exploration + T_final = 1e-7 # Very low final temperature + + # Parameters for localized FDR during SA + local_fdr_iterations = 15 # A few more internal FDR steps for better local optimization + local_fdr_repulsion_strength = 0.02 + local_fdr_boundary_strength = 0.05 + + # Adaptive number of neighbors for localized FDR + num_neighbors_initial = 3 # Main circle + 3 closest neighbors = 4 circles + num_neighbors_final = 1 # Main circle + 1 closest neighbor = 2 circles + + # Adaptive global perturbation strength (influences local FDR parameters) + initial_global_perturb_strength = 0.04 # Slightly increased for initial SA exploration + final_global_perturb_strength = 0.0002 # Very small for fine-tuning towards the end + + for iteration in range(total_sa_iterations): + # Decay global perturbation strength and temperature + global_perturb_strength = initial_global_perturb_strength * (1 - iteration / total_sa_iterations) + final_global_perturb_strength * (iteration / total_sa_iterations) + temperature = T_initial * (T_final / T_initial)**(iteration / total_sa_iterations) + + candidate_centers = current_centers.copy() + + # Select a circle to perturb using adaptive criteria (smaller radii more likely) + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + main_circle_idx = np.random.choice(n, p=selection_probs) + + # Determine the number of neighbors for localized FDR + current_num_neighbors = round(num_neighbors_initial * (1 - iteration / total_sa_iterations) + num_neighbors_final * (iteration / total_sa_iterations)) + + # Identify the group of circles for localized FDR (main_circle_idx + its closest neighbors) + distances_from_main = np.linalg.norm(current_centers - current_centers[main_circle_idx], axis=1) + # Sort distances and pick closest (excluding itself) + closest_indices = np.argsort(distances_from_main) + + affected_indices = [main_circle_idx] + count = 0 + for idx in closest_indices: + if idx == main_circle_idx: + continue + if count < current_num_neighbors: + affected_indices.append(idx) + count += 1 + else: + break + affected_indices = np.array(affected_indices) + + # Adapt local FDR step_size and thresholds based on SA's global_perturb_strength + # Larger global_perturb_strength means larger steps and broader interaction range for local FDR + local_fdr_step_size = global_perturb_strength * 0.1 # Scale step_size by global perturb + + # Repulsion threshold and boundary margin for local FDR also adapt + # They will be larger (more interaction) at the beginning of SA and smaller (finer interaction) towards the end + current_local_fdr_repulsion_threshold = 0.15 + global_perturb_strength * 2 + current_local_fdr_boundary_margin = 0.02 + global_perturb_strength * 0.5 + + + # Apply localized Force-Directed Relaxation to the selected group + candidate_centers = _apply_force_directed_relaxation( + candidate_centers, + n=n, + iterations=local_fdr_iterations, + step_size=local_fdr_step_size, + repulsion_strength=local_fdr_repulsion_strength, + repulsion_threshold=current_local_fdr_repulsion_threshold, + boundary_strength=local_fdr_boundary_strength, + boundary_margin=current_local_fdr_boundary_margin, + affected_indices=affected_indices + ) + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + else: + delta = candidate_sum_radii - current_sum_radii + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + # print(f"SA Iter {iteration}: New best sum of radii: {best_sum_radii:.4f}") + + # 3. Global Multi-stage Force-Directed Refinement (Deterministic Fine-Tuning) + # This phase polishes the arrangement found by SA, which serves as an excellent starting point. + + # Stage 1: Initial broad refinement + refined_centers = _apply_force_directed_relaxation( + best_centers.copy(), + n=n, + iterations=400, # Increased iterations + step_size=0.0012, # Slightly more aggressive step + repulsion_strength=0.009, + repulsion_threshold=0.185, # Broader repulsion + boundary_strength=0.04, + boundary_margin=0.035 + ) + + # Stage 2: Fine-tuning + refined_centers = _apply_force_directed_relaxation( + refined_centers, + n=n, + iterations=600, # Increased iterations + step_size=0.0006, + repulsion_strength=0.004, + repulsion_threshold=0.178, # Tighter repulsion + boundary_strength=0.02, + boundary_margin=0.02 + ) + + # Stage 3: Ultra-fine polish (gentle, long-duration) + refined_centers = _apply_force_directed_relaxation( + refined_centers, + n=n, + iterations=1000, # More iterations for final polish + step_size=0.0001, + repulsion_strength=0.001, + repulsion_threshold=0.17, # Very tight repulsion + boundary_strength=0.005, + boundary_margin=0.005 # Hugging edges + ) + + final_radii = compute_max_radii(refined_centers) + final_sum_radii = np.sum(final_radii) + + # Return the best from SA (which might be better if refinement overshot) + # or the result after final refinement, whichever yielded a higher sum. + if final_sum_radii > best_sum_radii: + return refined_centers, final_radii + else: + return best_centers, best_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..42a0bcfec3dc27c651a8d9fec540957564d23fa3 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..38c560ac8c13149f35754bef92c14a99ba3b789a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/edit.diff @@ -0,0 +1,206 @@ +--- a/original.py ++++ b/original.py +@@ -1,153 +1,180 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + # This function remains largely the same as it is a robust way to evaluate a given center configuration. + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + # This ensures the ratio of radii is maintained if possible + # while eliminating overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 +- radii[i] = 0 +- radii[j] = 0 +- +- changes_made = True ++ # Only set changes_made if they weren't already exactly 0 ++ if radii[i] > 1e-12 or radii[j] > 1e-12: ++ radii[i] = 0 ++ radii[j] = 0 ++ changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using an iterative + local search algorithm with targeted perturbations and greedy acceptance, + starting from an asymmetric Gaussian-deformed grid. This combines the + successful local search strategy with a robust radii computation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Initial Grid Generation (from the high-scoring prior program) + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Asymmetric void to break symmetry and provide a starting point for rearrangement + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 # Amplitude from the high-scoring prior + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + initial_centers = np.clip(initial_centers, 0.0, 1.0) + +- # 2. Iterative Local Search Optimization (from the high-scoring prior program) ++ # 2. Iterative Local Search with Simulated Annealing ++ # This replaces the greedy search with SA to escape local optima, ++ # inspired by the rigid structure seen in the visualization. + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + +- # Main parameters for the local search +- total_iterations = 8000 # High number of iterations for thorough search +- initial_perturb_strength = 0.02 # Initial maximum perturbation for exploration +- final_perturb_strength = 0.0005 # Final minimum perturbation for fine-tuning ++ # SA requires tracking the current state, which can temporarily worsen. ++ current_centers = initial_centers.copy() ++ current_radii = best_radii.copy() ++ current_sum_radii = best_sum_radii ++ ++ # Parameters inspired by high-scoring previous attempts, tuned for more exploration. ++ total_iterations = 12000 ++ initial_perturb_strength = 0.03 # Increased for more exploration ++ final_perturb_strength = 0.0005 ++ ++ # SA Temperature Schedule ++ T_initial = 0.1 # Higher temperature to accept more worse moves early on ++ T_final = 1e-6 # Very low final temperature for greedy-like refinement + + for iteration in range(total_iterations): +- # Linearly decay perturbation strength over iterations ++ # Linearly decay perturbation strength + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + +- candidate_centers = best_centers.copy() ++ # Exponentially decay temperature ++ temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + +- # Target circles that are currently small (more likely to be stuck). +- # This biases the search towards improving less optimized parts of the packing. +- # Calculate inverse radii, normalize to get probabilities. +- # Add a small constant to avoid division by zero for radius 0. +- inverse_radii = 1 / (best_radii + 1e-8) # Using best_radii from previous best state ++ # Perturb from the current state, not the best state ++ candidate_centers = current_centers.copy() ++ ++ # Target circles based on the current radii to guide the ongoing search ++ inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # Select a circle to perturb based on its probability + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + +- # Greedy acceptance: if the new configuration is better, accept it +- if candidate_sum_radii > best_sum_radii: +- best_sum_radii = candidate_sum_radii +- best_centers = candidate_centers.copy() +- best_radii = candidate_radii.copy() # Update best_radii for future selection probabilities +- # Uncomment for debugging: +- # print(f"Iter {iteration}: New best sum of radii: {best_sum_radii:.4f}") ++ # Simulated Annealing acceptance criteria ++ if candidate_sum_radii > current_sum_radii: ++ # Always accept a better solution ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers.copy() ++ current_radii = candidate_radii.copy() ++ else: ++ # Accept a worse solution with a probability dependent on temperature ++ delta = candidate_sum_radii - current_sum_radii # This is negative ++ if temperature > 1e-9: # Avoid division by zero ++ acceptance_prob = np.exp(delta / temperature) ++ if np.random.rand() < acceptance_prob: ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers.copy() ++ current_radii = candidate_radii.copy() ++ ++ # Update the globally best solution found so far ++ if current_sum_radii > best_sum_radii: ++ best_sum_radii = current_sum_radii ++ best_centers = current_centers.copy() ++ best_radii = current_radii.copy() + + return best_centers, best_radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/main.py new file mode 100644 index 0000000000000000000000000000000000000000..62fbc9cb9eae9763e2d8e9a0a320a436c9b80e97 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/main.py @@ -0,0 +1,180 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + +# This function remains largely the same as it is a robust way to evaluate a given center configuration. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + # This ensures the ratio of radii is maintained if possible + # while eliminating overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + # Only set changes_made if they weren't already exactly 0 + if radii[i] > 1e-12 or radii[j] > 1e-12: + radii[i] = 0 + radii[j] = 0 + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using an iterative + local search algorithm with targeted perturbations and greedy acceptance, + starting from an asymmetric Gaussian-deformed grid. This combines the + successful local search strategy with a robust radii computation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Initial Grid Generation (from the high-scoring prior program) + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Asymmetric void to break symmetry and provide a starting point for rearrangement + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 # Amplitude from the high-scoring prior + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + initial_centers = np.clip(initial_centers, 0.0, 1.0) + + # 2. Iterative Local Search with Simulated Annealing + # This replaces the greedy search with SA to escape local optima, + # inspired by the rigid structure seen in the visualization. + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + # SA requires tracking the current state, which can temporarily worsen. + current_centers = initial_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Parameters inspired by high-scoring previous attempts, tuned for more exploration. + total_iterations = 12000 + initial_perturb_strength = 0.03 # Increased for more exploration + final_perturb_strength = 0.0005 + + # SA Temperature Schedule + T_initial = 0.1 # Higher temperature to accept more worse moves early on + T_final = 1e-6 # Very low final temperature for greedy-like refinement + + for iteration in range(total_iterations): + # Linearly decay perturbation strength + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + # Exponentially decay temperature + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + # Perturb from the current state, not the best state + candidate_centers = current_centers.copy() + + # Target circles based on the current radii to guide the ongoing search + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # Select a circle to perturb based on its probability + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + if candidate_sum_radii > current_sum_radii: + # Always accept a better solution + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + else: + # Accept a worse solution with a probability dependent on temperature + delta = candidate_sum_radii - current_sum_radii # This is negative + if temperature > 1e-9: # Avoid division by zero + acceptance_prob = np.exp(delta / temperature) + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + + # Update the globally best solution found so far + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/original.py new file mode 100644 index 0000000000000000000000000000000000000000..e83858d73c65d8e2eb068f518babe9a0609cf28c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/original.py @@ -0,0 +1,153 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + +# This function remains largely the same as it is a robust way to evaluate a given center configuration. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + # This ensures the ratio of radii is maintained if possible + # while eliminating overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using an iterative + local search algorithm with targeted perturbations and greedy acceptance, + starting from an asymmetric Gaussian-deformed grid. This combines the + successful local search strategy with a robust radii computation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Initial Grid Generation (from the high-scoring prior program) + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Asymmetric void to break symmetry and provide a starting point for rearrangement + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 # Amplitude from the high-scoring prior + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + initial_centers = np.clip(initial_centers, 0.0, 1.0) + + # 2. Iterative Local Search Optimization (from the high-scoring prior program) + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + # Main parameters for the local search + total_iterations = 8000 # High number of iterations for thorough search + initial_perturb_strength = 0.02 # Initial maximum perturbation for exploration + final_perturb_strength = 0.0005 # Final minimum perturbation for fine-tuning + + for iteration in range(total_iterations): + # Linearly decay perturbation strength over iterations + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + candidate_centers = best_centers.copy() + + # Target circles that are currently small (more likely to be stuck). + # This biases the search towards improving less optimized parts of the packing. + # Calculate inverse radii, normalize to get probabilities. + # Add a small constant to avoid division by zero for radius 0. + inverse_radii = 1 / (best_radii + 1e-8) # Using best_radii from previous best state + selection_probs = inverse_radii / np.sum(inverse_radii) + + # Select a circle to perturb based on its probability + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Greedy acceptance: if the new configuration is better, accept it + if candidate_sum_radii > best_sum_radii: + best_sum_radii = candidate_sum_radii + best_centers = candidate_centers.copy() + best_radii = candidate_radii.copy() # Update best_radii for future selection probabilities + # Uncomment for debugging: + # print(f"Iter {iteration}: New best sum of radii: {best_sum_radii:.4f}") + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..ad42a57eaa9264189f100e04577ec029d9ffd504 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_134/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_134/results +Run 1/1 completed in 24.68 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.2915351947328837 + public: {'centers_str': ' centers[0] = (0.1140, 0.0529)\n centers[1] = (0.0681, 0.1648)\n centers[2] = (0.4933, 0.0771)\n centers[3] = (0.6503, 0.3498)\n centers[4] = (0.8997, 0.1005)\n centers[5] = (0.0721, 0.3048)\n centers[6] = (0.2740, 0.4073)\n centers[7] = (0.5037, 0.3315)\n centers[8] = (0.6545, 0.1337)\n centers[9] = (0.8412, 0.3259)\n centers[10] = (0.0554, 0.4212)\n centers[11] = (0.1560, 0.4989)\n centers[12] = (0.7305, 0.8232)\n centers[13] = (0.6417, 0.5060)\n centers[14] = (0.8998, 0.5529)\n centers[15] = (0.1219, 0.6894)\n centers[16] = (0.3653, 0.5656)\n centers[17] = (0.5608, 0.7387)\n centers[18] = (0.7678, 0.6996)\n centers[19] = (0.6962, 0.9248)\n centers[20] = (0.0952, 0.9052)\n centers[21] = (0.3286, 0.8557)\n centers[22] = (0.4552, 0.9720)\n centers[23] = (0.5466, 0.9252)\n centers[24] = (0.8831, 0.8803)\n centers[25] = (0.3055, 0.1748)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.2915351947328837} + visualization_path: + execution_time_mean: 24.680674452800304 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..0a3df7614167285b6c5e50e63b72da3ef6f46f0b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.2915351947328837, + "public": { + "centers_str": " centers[0] = (0.1140, 0.0529)\n centers[1] = (0.0681, 0.1648)\n centers[2] = (0.4933, 0.0771)\n centers[3] = (0.6503, 0.3498)\n centers[4] = (0.8997, 0.1005)\n centers[5] = (0.0721, 0.3048)\n centers[6] = (0.2740, 0.4073)\n centers[7] = (0.5037, 0.3315)\n centers[8] = (0.6545, 0.1337)\n centers[9] = (0.8412, 0.3259)\n centers[10] = (0.0554, 0.4212)\n centers[11] = (0.1560, 0.4989)\n centers[12] = (0.7305, 0.8232)\n centers[13] = (0.6417, 0.5060)\n centers[14] = (0.8998, 0.5529)\n centers[15] = (0.1219, 0.6894)\n centers[16] = (0.3653, 0.5656)\n centers[17] = (0.5608, 0.7387)\n centers[18] = (0.7678, 0.6996)\n centers[19] = (0.6962, 0.9248)\n centers[20] = (0.0952, 0.9052)\n centers[21] = (0.3286, 0.8557)\n centers[22] = (0.4552, 0.9720)\n centers[23] = (0.5466, 0.9252)\n centers[24] = (0.8831, 0.8803)\n centers[25] = (0.3055, 0.1748)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.2915351947328837 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_134/results/packing_viz.png", + "execution_time_mean": 24.680674452800304, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..e547831a7312e994472085f7e9f09f2bf5681797 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_134/search_replace.txt @@ -0,0 +1,181 @@ +Based on my analysis of the provided visualization and my expertise in computational geometry, the current algorithm is getting trapped in a local optimum. The arrangement is too grid-like, a clear artifact of the initialization process. The central area is particularly inefficient, with a large circle surrounded by smaller ones, a classic sign of a suboptimal packing. To overcome this, the search algorithm needs to be more exploratory. + +My primary recommendation is to replace the current greedy local search with a Simulated Annealing (SA) algorithm. SA allows the search to accept temporarily worse solutions, giving it the "energy" to escape local minima like the one observed and explore more diverse, potentially superior configurations. I will also make a minor corrective change to the `compute_max_radii` function to improve its efficiency and correctness. + + +fix_radii_convergence_logic + + + +This edit corrects a logical error in the `compute_max_radii` function. The `changes_made` flag was being set unconditionally within the overlap-check block, even when no actual change to the radii occurred. This could prevent the iterative process from terminating early when a stable state was reached, leading to unnecessary computation. The fix ensures the flag is set only when a radius value is demonstrably reduced, making the convergence check accurate. + + + +<<<<<<< SEARCH + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + # This ensures the ratio of radii is maintained if possible + # while eliminating overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True +======= + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + # This ensures the ratio of radii is maintained if possible + # while eliminating overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + # Only set changes_made if they weren't already exactly 0 + if radii[i] > 1e-12 or radii[j] > 1e-12: + radii[i] = 0 + radii[j] = 0 + changes_made = True +>>>>>>> REPLACE + + +implement_simulated_annealing + + + +This change replaces the core optimization algorithm from a purely greedy local search to Simulated Annealing (SA). The visualization clearly shows the greedy search is stuck in a rigid, grid-like local optimum. By introducing a temperature schedule and probabilistically accepting worse moves, SA can escape these traps and explore a much wider range of configurations. The parameters for SA (iteration count, temperature, and perturbation strength) have been tuned to encourage aggressive exploration at the beginning to break the initial grid structure, and then gradually cool down to fine-tune the solution. This directly addresses the main weakness identified in the visual analysis. + + + +<<<<<<< SEARCH + # 2. Iterative Local Search Optimization (from the high-scoring prior program) + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + # Main parameters for the local search + total_iterations = 8000 # High number of iterations for thorough search + initial_perturb_strength = 0.02 # Initial maximum perturbation for exploration + final_perturb_strength = 0.0005 # Final minimum perturbation for fine-tuning + + for iteration in range(total_iterations): + # Linearly decay perturbation strength over iterations + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + candidate_centers = best_centers.copy() + + # Target circles that are currently small (more likely to be stuck). + # This biases the search towards improving less optimized parts of the packing. + # Calculate inverse radii, normalize to get probabilities. + # Add a small constant to avoid division by zero for radius 0. + inverse_radii = 1 / (best_radii + 1e-8) # Using best_radii from previous best state + selection_probs = inverse_radii / np.sum(inverse_radii) + + # Select a circle to perturb based on its probability + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Greedy acceptance: if the new configuration is better, accept it + if candidate_sum_radii > best_sum_radii: + best_sum_radii = candidate_sum_radii + best_centers = candidate_centers.copy() + best_radii = candidate_radii.copy() # Update best_radii for future selection probabilities + # Uncomment for debugging: + # print(f"Iter {iteration}: New best sum of radii: {best_sum_radii:.4f}") + + return best_centers, best_radii +======= + # 2. Iterative Local Search with Simulated Annealing + # This replaces the greedy search with SA to escape local optima, + # inspired by the rigid structure seen in the visualization. + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + # SA requires tracking the current state, which can temporarily worsen. + current_centers = initial_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Parameters inspired by high-scoring previous attempts, tuned for more exploration. + total_iterations = 12000 + initial_perturb_strength = 0.03 # Increased for more exploration + final_perturb_strength = 0.0005 + + # SA Temperature Schedule + T_initial = 0.1 # Higher temperature to accept more worse moves early on + T_final = 1e-6 # Very low final temperature for greedy-like refinement + + for iteration in range(total_iterations): + # Linearly decay perturbation strength + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + # Exponentially decay temperature + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + # Perturb from the current state, not the best state + candidate_centers = current_centers.copy() + + # Target circles based on the current radii to guide the ongoing search + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # Select a circle to perturb based on its probability + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + if candidate_sum_radii > current_sum_radii: + # Always accept a better solution + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + else: + # Accept a worse solution with a probability dependent on temperature + delta = candidate_sum_radii - current_sum_radii # This is negative + if temperature > 1e-9: # Avoid division by zero + acceptance_prob = np.exp(delta / temperature) + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + + # Update the globally best solution found so far + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + return best_centers, best_radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a50e723953e363170fd3310cd2aee78a21c9e41 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..449e7abe31c3e1e5045221361cee3afad21ebfff --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_135/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_135/results +Run 1/1 completed in 21.15 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.174949054223052 + public: {'centers_str': ' centers[0] = (0.0886, 0.0889)\n centers[1] = (0.2190, 0.0481)\n centers[2] = (0.6086, 0.1052)\n centers[3] = (0.7598, 0.0489)\n centers[4] = (0.8998, 0.1000)\n centers[5] = (0.0885, 0.2660)\n centers[6] = (0.2609, 0.3893)\n centers[7] = (0.5329, 0.4049)\n centers[8] = (0.7157, 0.2002)\n centers[9] = (0.8994, 0.3004)\n centers[10] = (0.0904, 0.4874)\n centers[11] = (0.2868, 0.5433)\n centers[12] = (0.5810, 0.6103)\n centers[13] = (0.7056, 0.4548)\n centers[14] = (0.9003, 0.5001)\n centers[15] = (0.1003, 0.6938)\n centers[16] = (0.3054, 0.6994)\n centers[17] = (0.4991, 0.7084)\n centers[18] = (0.6933, 0.6653)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1004, 0.8954)\n centers[21] = (0.2981, 0.9026)\n centers[22] = (0.4970, 0.8988)\n centers[23] = (0.6999, 0.8982)\n centers[24] = (0.9007, 0.8998)\n centers[25] = (0.4010, 0.2061)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.174949054223052} + visualization_path: + execution_time_mean: 21.14831196097657 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..2b2a94f730f8d7cbdf5e74baaa5d11dd74f8d56b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.174949054223052, + "public": { + "centers_str": " centers[0] = (0.0886, 0.0889)\n centers[1] = (0.2190, 0.0481)\n centers[2] = (0.6086, 0.1052)\n centers[3] = (0.7598, 0.0489)\n centers[4] = (0.8998, 0.1000)\n centers[5] = (0.0885, 0.2660)\n centers[6] = (0.2609, 0.3893)\n centers[7] = (0.5329, 0.4049)\n centers[8] = (0.7157, 0.2002)\n centers[9] = (0.8994, 0.3004)\n centers[10] = (0.0904, 0.4874)\n centers[11] = (0.2868, 0.5433)\n centers[12] = (0.5810, 0.6103)\n centers[13] = (0.7056, 0.4548)\n centers[14] = (0.9003, 0.5001)\n centers[15] = (0.1003, 0.6938)\n centers[16] = (0.3054, 0.6994)\n centers[17] = (0.4991, 0.7084)\n centers[18] = (0.6933, 0.6653)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1004, 0.8954)\n centers[21] = (0.2981, 0.9026)\n centers[22] = (0.4970, 0.8988)\n centers[23] = (0.6999, 0.8982)\n centers[24] = (0.9007, 0.8998)\n centers[25] = (0.4010, 0.2061)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.174949054223052 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_135/results/packing_viz.png", + "execution_time_mean": 21.14831196097657, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cda6edc3174a80416dabe517b7dfbf4c7b7dd0b7 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..bef3eeb8e355b54689a0029865ef0d64c64bc4e4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/edit.diff @@ -0,0 +1,319 @@ +--- a/original.py ++++ b/original.py +@@ -1,271 +1,309 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + + class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Create masks for interaction + # upper_tri_mask avoids duplicate calculations (i,j and j,i) and self-interaction (i,i) + upper_tri_mask = np.triu(np.ones((self.n, self.n), dtype=bool), k=1) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) & upper_tri_mask + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors + # Ensure division by dists is only for non-zero distances + normalized_diff = np.zeros_like(diff) + non_zero_dists = dists > 1e-9 + normalized_diff[non_zero_dists] = diff[non_zero_dists] / dists[non_zero_dists, np.newaxis] + + force_vectors = force_magnitudes[:, :, np.newaxis] * normalized_diff + + # Sum forces from other circles + # Forces are symmetric, so F_ij = -F_ji. Summing only upper triangle forces + # means we need to apply F_ij to i and -F_ij to j. + # A more direct way is to sum all forces, which intrinsically handles F_ij and F_ji correctly + # as F_ij + F_ji will be 0, but summing just F_ij means we are building F_i for all j. + # `np.sum(force_vectors, axis=1)` already sums F_ij over j for each i. + # This is correct if `force_magnitudes` for `j,i` is same as `i,j` (which it is if it's based on dist). + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + ++ cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation ++ + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) +- perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) ++ base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero + selection_probs = inverse_radii / np.sum(inverse_radii) +- circle_idx = np.random.choice(self.n, p=selection_probs) +- +- # Apply a random displacement +- displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) +- candidate_centers[circle_idx] += displacement +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) ++ ++ # --- Clustered or Single Circle Perturbation --- ++ if np.random.rand() < cluster_perturb_prob: ++ # Clustered perturbation: select a primary circle, then its nearest neighbors ++ primary_idx = np.random.choice(self.n, p=selection_probs) ++ ++ # Find the 2 closest neighbors (excluding self) ++ distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) ++ # Use argsort to get indices of circles sorted by distance ++ # Skip the first element which is the primary_idx itself (distance 0) ++ neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors ++ ++ # Collect all indices to perturb: primary + neighbors ++ indices_to_perturb = [primary_idx] ++ indices_to_perturb.extend(neighbor_indices) ++ ++ # Calculate adaptive perturbation strength based on the primary circle's inverse radius ++ avg_inverse_radius = np.mean(inverse_radii) ++ scale_factor = inverse_radii[primary_idx] / avg_inverse_radius ++ # Clamp the scale factor to prevent excessively large or small perturbations. ++ effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) ++ ++ # Generate a single displacement vector for the entire cluster ++ displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) ++ ++ # Apply the displacement to all circles in the cluster ++ for idx in indices_to_perturb: ++ candidate_centers[idx] += displacement ++ candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) ++ else: ++ # Single circle perturbation ++ circle_idx = np.random.choice(self.n, p=selection_probs) ++ ++ # Apply adaptive perturbation strength based on the selected circle's inverse radius ++ avg_inverse_radius = np.mean(inverse_radii) ++ scale_factor = inverse_radii[circle_idx] / avg_inverse_radius ++ effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) ++ ++ # Apply a random displacement ++ displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Randomized initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # --- Initialization Stage --- + # Randomly choose a void center to avoid fixed patterns and explore more initial states. + # Restrict void_center to central region to avoid pushing circles outside the square too much. + random_void_center = np.random.uniform(0.3, 0.7, 2) + + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, + amplitude=0.08, # Increased amplitude for stronger initial push + sigma=0.15 + ) + + # --- Phase 1: Quick Force-Directed Relaxation (Pre-optimization) --- + # Applies a quick, aggressive force-directed relaxation to resolve initial overlaps + # and settle the configuration into a more stable state before SA. + self._force_directed_relaxation_vectorized( + iters=500, # Sufficient to resolve initial chaos + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # --- Phase 2: Simulated Annealing Local Search --- + # This is the primary optimization phase, designed to escape local optima. + self._simulated_annealing_search( + total_iterations=12000, # Increased iterations for thorough SA search + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # --- Phase 3: Final Gentle Force-Directed Relaxation (Post-optimization) --- + # After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact, + # as SA optimizes sum of radii which might not be perfectly packed. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + This function now acts as a client to the CirclePacker class, simplifying top-level logic. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/main.py new file mode 100644 index 0000000000000000000000000000000000000000..3972e8d85e29423b63879d75579cce10a1846a15 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/main.py @@ -0,0 +1,309 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Create masks for interaction + # upper_tri_mask avoids duplicate calculations (i,j and j,i) and self-interaction (i,i) + upper_tri_mask = np.triu(np.ones((self.n, self.n), dtype=bool), k=1) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) & upper_tri_mask + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors + # Ensure division by dists is only for non-zero distances + normalized_diff = np.zeros_like(diff) + non_zero_dists = dists > 1e-9 + normalized_diff[non_zero_dists] = diff[non_zero_dists] / dists[non_zero_dists, np.newaxis] + + force_vectors = force_magnitudes[:, :, np.newaxis] * normalized_diff + + # Sum forces from other circles + # Forces are symmetric, so F_ij = -F_ji. Summing only upper triangle forces + # means we need to apply F_ij to i and -F_ij to j. + # A more direct way is to sum all forces, which intrinsically handles F_ij and F_ji correctly + # as F_ij + F_ji will be 0, but summing just F_ij means we are building F_i for all j. + # `np.sum(force_vectors, axis=1)` already sums F_ij over j for each i. + # This is correct if `force_magnitudes` for `j,i` is same as `i,j` (which it is if it's based on dist). + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Randomized initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # --- Initialization Stage --- + # Randomly choose a void center to avoid fixed patterns and explore more initial states. + # Restrict void_center to central region to avoid pushing circles outside the square too much. + random_void_center = np.random.uniform(0.3, 0.7, 2) + + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, + amplitude=0.08, # Increased amplitude for stronger initial push + sigma=0.15 + ) + + # --- Phase 1: Quick Force-Directed Relaxation (Pre-optimization) --- + # Applies a quick, aggressive force-directed relaxation to resolve initial overlaps + # and settle the configuration into a more stable state before SA. + self._force_directed_relaxation_vectorized( + iters=500, # Sufficient to resolve initial chaos + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # --- Phase 2: Simulated Annealing Local Search --- + # This is the primary optimization phase, designed to escape local optima. + self._simulated_annealing_search( + total_iterations=12000, # Increased iterations for thorough SA search + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # --- Phase 3: Final Gentle Force-Directed Relaxation (Post-optimization) --- + # After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact, + # as SA optimizes sum of radii which might not be perfectly packed. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + This function now acts as a client to the CirclePacker class, simplifying top-level logic. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/original.py new file mode 100644 index 0000000000000000000000000000000000000000..57bbabe93d111e59ca8623a9d8bdf52ac594083b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/original.py @@ -0,0 +1,271 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Create masks for interaction + # upper_tri_mask avoids duplicate calculations (i,j and j,i) and self-interaction (i,i) + upper_tri_mask = np.triu(np.ones((self.n, self.n), dtype=bool), k=1) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) & upper_tri_mask + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors + # Ensure division by dists is only for non-zero distances + normalized_diff = np.zeros_like(diff) + non_zero_dists = dists > 1e-9 + normalized_diff[non_zero_dists] = diff[non_zero_dists] / dists[non_zero_dists, np.newaxis] + + force_vectors = force_magnitudes[:, :, np.newaxis] * normalized_diff + + # Sum forces from other circles + # Forces are symmetric, so F_ij = -F_ji. Summing only upper triangle forces + # means we need to apply F_ij to i and -F_ij to j. + # A more direct way is to sum all forces, which intrinsically handles F_ij and F_ji correctly + # as F_ij + F_ji will be 0, but summing just F_ij means we are building F_i for all j. + # `np.sum(force_vectors, axis=1)` already sums F_ij over j for each i. + # This is correct if `force_magnitudes` for `j,i` is same as `i,j` (which it is if it's based on dist). + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply a random displacement + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Randomized initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # --- Initialization Stage --- + # Randomly choose a void center to avoid fixed patterns and explore more initial states. + # Restrict void_center to central region to avoid pushing circles outside the square too much. + random_void_center = np.random.uniform(0.3, 0.7, 2) + + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, + amplitude=0.08, # Increased amplitude for stronger initial push + sigma=0.15 + ) + + # --- Phase 1: Quick Force-Directed Relaxation (Pre-optimization) --- + # Applies a quick, aggressive force-directed relaxation to resolve initial overlaps + # and settle the configuration into a more stable state before SA. + self._force_directed_relaxation_vectorized( + iters=500, # Sufficient to resolve initial chaos + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # --- Phase 2: Simulated Annealing Local Search --- + # This is the primary optimization phase, designed to escape local optima. + self._simulated_annealing_search( + total_iterations=12000, # Increased iterations for thorough SA search + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # --- Phase 3: Final Gentle Force-Directed Relaxation (Post-optimization) --- + # After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact, + # as SA optimizes sum of radii which might not be perfectly packed. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + This function now acts as a client to the CirclePacker class, simplifying top-level logic. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..dee0f5965ebf4a849e96ff4f13392080cad42972 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_136/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_136/results +Run 1/1 completed in 26.11 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.177669823417585 + public: {'centers_str': ' centers[0] = (0.0944, 0.0941)\n centers[1] = (0.2836, 0.0951)\n centers[2] = (0.4910, 0.1130)\n centers[3] = (0.6979, 0.0947)\n centers[4] = (0.9072, 0.0928)\n centers[5] = (0.0355, 0.2094)\n centers[6] = (0.1094, 0.3029)\n centers[7] = (0.5981, 0.2458)\n centers[8] = (0.7637, 0.1859)\n centers[9] = (0.9035, 0.2894)\n centers[10] = (0.0590, 0.4431)\n centers[11] = (0.2470, 0.5460)\n centers[12] = (0.5300, 0.5990)\n centers[13] = (0.6916, 0.3978)\n centers[14] = (0.8895, 0.5010)\n centers[15] = (0.0927, 0.6701)\n centers[16] = (0.2937, 0.6889)\n centers[17] = (0.4876, 0.7299)\n centers[18] = (0.6859, 0.6557)\n centers[19] = (0.9055, 0.7054)\n centers[20] = (0.1002, 0.8996)\n centers[21] = (0.3014, 0.8990)\n centers[22] = (0.4971, 0.9053)\n centers[23] = (0.6959, 0.8956)\n centers[24] = (0.9001, 0.8998)\n centers[25] = (0.3814, 0.3463)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.177669823417585} + visualization_path: + execution_time_mean: 26.113690755795687 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..0b56197c8ba2e921dbc0c9c9167ed0ef82be4c71 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.177669823417585, + "public": { + "centers_str": " centers[0] = (0.0944, 0.0941)\n centers[1] = (0.2836, 0.0951)\n centers[2] = (0.4910, 0.1130)\n centers[3] = (0.6979, 0.0947)\n centers[4] = (0.9072, 0.0928)\n centers[5] = (0.0355, 0.2094)\n centers[6] = (0.1094, 0.3029)\n centers[7] = (0.5981, 0.2458)\n centers[8] = (0.7637, 0.1859)\n centers[9] = (0.9035, 0.2894)\n centers[10] = (0.0590, 0.4431)\n centers[11] = (0.2470, 0.5460)\n centers[12] = (0.5300, 0.5990)\n centers[13] = (0.6916, 0.3978)\n centers[14] = (0.8895, 0.5010)\n centers[15] = (0.0927, 0.6701)\n centers[16] = (0.2937, 0.6889)\n centers[17] = (0.4876, 0.7299)\n centers[18] = (0.6859, 0.6557)\n centers[19] = (0.9055, 0.7054)\n centers[20] = (0.1002, 0.8996)\n centers[21] = (0.3014, 0.8990)\n centers[22] = (0.4971, 0.9053)\n centers[23] = (0.6959, 0.8956)\n centers[24] = (0.9001, 0.8998)\n centers[25] = (0.3814, 0.3463)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.177669823417585 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_136/results/packing_viz.png", + "execution_time_mean": 26.113690755795687, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..5e4e354d65a67a799151c70954c38df0c3530141 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_136/search_replace.txt @@ -0,0 +1,89 @@ + +Reintroduce cooperative multi-circle perturbation and adaptive perturbation strength. +This change re-implements a strategy from a previously successful generation where, with a certain probability, a small cluster of circles (a primary circle and its two closest neighbors) is perturbed together. This helps "unstuck" groups of circles and allows for more complex, coordinated movements that single-circle perturbations struggle to find. Additionally, the perturbation strength for both single and clustered movements is made adaptive to the circle's size, with smaller circles receiving potentially larger perturbations to help them grow or escape local minima. This addresses the visual observation of small, "trapped" circles and potentially underutilized space that could benefit from group movements. + + +<<<<<<< SEARCH + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply a random displacement + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +======= + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c41efe6e36dff830646c91b537e6f249162ee211 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..dcbd83c23bfac740209c96a6df09e1e3b848ffa3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/edit.diff @@ -0,0 +1,401 @@ +--- a/original.py ++++ b/original.py +@@ -1,159 +1,287 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" ++"""Constructor-based circle packing for n=26 circles using Modular Simulated Annealing local search""" + + import numpy as np + +- +-def construct_packing(): +- """ +- Construct a specific arrangement of 26 circles in a unit square +- that attempts to maximize the sum of their radii. +- +- Returns: +- Tuple of (centers, radii, sum_of_radii) +- centers: np.array of shape (26, 2) with (x, y) coordinates +- radii: np.array of shape (26) with radius of each circle +- sum_of_radii: Sum of all radii +- """ +- # Initialize arrays for 26 circles +- n = 26 +- centers = np.zeros((n, 2)) +- +- # 1. Start with the 25 centers of a 5x5 grid. +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T +- +- # 2. Define an ASYMMETRIC center for the void. +- # Breaking the initial symmetry by using an off-center void at (0.4, 0.2) +- # prevents the relaxation from getting stuck in an overly-ordered local optimum. +- void_center = np.array([0.4, 0.2]) +- +- # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. +- # This pushes nearby circles away to make more room. +- deformed_centers_25 = np.copy(base_centers_25) +- +- # Hyperparameters for the Gaussian push: +- amplitude = 0.06 # The maximum distance to push a circle. Increased to create a larger void. +- sigma = 0.15 # The "spread" of the push, controlling its influence range. +- +- for i in range(25): +- pos_vector = base_centers_25[i] - void_center +- dist_sq = np.sum(pos_vector**2) +- +- # Gaussian function defines the push magnitude based on distance from the void center. +- push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) +- +- # The push is directed radially away from the void center. +- if np.linalg.norm(pos_vector) > 1e-9: +- direction = pos_vector / np.linalg.norm(pos_vector) +- displacement = direction * push_magnitude +- deformed_centers_25[i] += displacement +- +- # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. +- centers[:25] = deformed_centers_25 +- centers[25] = void_center +- +- # Clip centers to ensure they stay within the square, although the push is gentle. +- centers = np.clip(centers, 0.0, 1.0) +- +- # 5. Iterative Local Search with Greedy Acceptance +- # Replace the ineffective force-directed method with a more robust local search. +- best_centers = centers.copy() +- best_radii = compute_max_radii(best_centers) +- best_sum_radii = np.sum(best_radii) +- +- # Parameters for the local search, inspired by prior successful models. +- total_iterations = 10000 +- initial_perturb_strength = 0.025 +- final_perturb_strength = 0.0005 +- +- for iteration in range(total_iterations): +- # Linearly anneal perturbation strength for exploration -> exploitation. +- perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) +- +- candidate_centers = best_centers.copy() +- +- # Target smaller circles, as they are more likely to be in suboptimal positions. +- inverse_radii = 1 / (best_radii + 1e-8) +- selection_probs = inverse_radii / np.sum(inverse_radii) +- +- circle_idx = np.random.choice(n, p=selection_probs) +- +- # Apply a random displacement. +- displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) +- candidate_centers[circle_idx] += displacement +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +- +- # Evaluate the new configuration. +- candidate_radii = compute_max_radii(candidate_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- # Greedy acceptance: only accept better solutions. +- if candidate_sum_radii > best_sum_radii: +- best_sum_radii = candidate_sum_radii +- best_centers = candidate_centers.copy() +- best_radii = candidate_radii.copy() +- +- # 6. Return the best configuration found by the local search. +- return best_centers, best_radii +- +- + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This version +- iteratively resolves conflicts until convergence for a more accurate result. ++ such that they don't overlap and stay within the unit square. This is ++ an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + +- # Vectorized initialization: radii are limited by distance to square borders. ++ # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + +- # Iteratively limit by distance to other circles, allowing constraints to propagate. +- for _ in range(500): # More iterations for better convergence. ++ # Iteratively resolve overlaps between circles until no more changes occur. ++ # A high number of iterations ensures convergence for complex arrangements. ++ for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale +- ++ + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True +- # This branch handles cases where radii are already near zero. +- elif radii[i] > 0 or radii[j] > 0: +- radii[i], radii[j] = 0, 0 +- changes_made = True +- ++ else: # If both radii are already ~0, ensure they are exactly 0 ++ # Only set changes_made if they weren't already exactly 0 ++ if radii[i] > 1e-12 or radii[j] > 1e-12: ++ radii[i] = 0 ++ radii[j] = 0 ++ changes_made = True ++ ++ # If a full pass resulted in no changes, the packing is stable. + if not changes_made: +- break # Exit early if the configuration is stable ++ break + + return radii + +- ++class CirclePacker: ++ """ ++ Encapsulates the logic for constructing a high-density arrangement of circles ++ using an asymmetric grid initialization, a pre-optimization force-directed ++ relaxation, and a Simulated Annealing local search with adaptive perturbations. ++ """ ++ def __init__(self, n): ++ self.n = n ++ self.centers = np.zeros((n, 2)) ++ self.radii = np.zeros(n) ++ self.sum_radii = 0.0 ++ ++ def _initialize_centers(self): ++ """ ++ Initializes circle centers using a Gaussian-deformed grid for 25 circles ++ and places the 26th in an asymmetric void. ++ """ ++ x_coords = np.linspace(0.1, 0.9, 5) ++ y_coords = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords, y_coords) ++ base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T ++ ++ # Asymmetric void adjusted to (0.3, 0.3) for varied initial exploration. ++ void_center = np.array([0.3, 0.3]) ++ amplitude = 0.07 # Slightly increased amplitude for a larger initial void. ++ sigma = 0.15 ++ ++ displacements = base_centers_25 - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ mask = distances > 1e-9 ++ ++ push_magnitudes = np.zeros(25) ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ ++ if np.any(mask): ++ displacements[mask] /= distances[mask, np.newaxis] ++ ++ self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ self.centers[25] = void_center ++ self.centers = np.clip(self.centers, 0.0, 1.0) # Ensure centers are within [0,1] square ++ self.radii = compute_max_radii(self.centers) ++ self.sum_radii = np.sum(self.radii) ++ ++ def _apply_force_directed_relaxation(self, centers_to_relax, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): ++ """ ++ Applies a force-directed relaxation algorithm to a set of circle centers. ++ Circles repel each other and are repelled by boundaries. ++ """ ++ n_local = centers_to_relax.shape[0] ++ for _ in range(iterations): ++ forces = np.zeros_like(centers_to_relax) ++ ++ # Circle-circle repulsion ++ for i in range(n_local): ++ for j in range(i + 1, n_local): ++ vec = centers_to_relax[i] - centers_to_relax[j] ++ dist = np.linalg.norm(vec) ++ # Increased repulsion threshold to encourage more spacing initially ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n_local): ++ x, y = centers_to_relax[i] ++ # Increased boundary strength to push centers closer to edges ++ if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers_to_relax += step_size * forces ++ centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) # Keep centers within bounds ++ return centers_to_relax ++ ++ def _select_circle_for_perturbation(self, current_radii, current_centers): ++ """ ++ Selects a circle to perturb based on its inverse radius and proximity to boundaries. ++ Smaller circles and those closer to boundaries have a higher chance of being selected. ++ """ ++ inverse_radii = 1 / (current_radii + 1e-8) ++ ++ # Calculate distance to nearest boundary for each circle ++ dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], ++ current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) ++ ++ # Exponentially weight circles closer to boundaries ++ # Reduced scale factor (0.07) to make boundary proximity more influential. ++ boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) ++ ++ # Combine inverse_radii and boundary proximity to get selection weights ++ combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) ++ selection_probs = combined_weights / np.sum(combined_weights) ++ ++ circle_idx = np.random.choice(self.n, p=selection_probs) ++ return circle_idx ++ ++ def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): ++ """ ++ Calculates an adaptive perturbation strength for a specific circle. ++ Smaller circles receive a proportionally larger perturbation to help them ++ escape local minima. ++ """ ++ max_r = np.max(current_radii) + 1e-8 # Avoid division by zero ++ relative_radius = current_radii[circle_idx] / max_r ++ ++ # Perturbation factor: 1.0 for the largest circle, up to 3.0 for the smallest. ++ # Increased multiplier (2.0) for more aggressive movement of small circles. ++ perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 ++ ++ return global_perturb_strength * perturb_factor ++ ++ def pack(self): ++ """ ++ Executes the full packing process: initialization, pre-optimization, ++ and Simulated Annealing. ++ """ ++ self._initialize_centers() ++ ++ # Pre-optimization with a short, mild Force-Directed Relaxation stage ++ self.centers = self._apply_force_directed_relaxation( ++ self.centers.copy(), ++ iterations=750, # Increased iterations for F-D ++ step_size=0.0015, # Slightly increased step size ++ repulsion_strength=0.012, # Slightly increased repulsion ++ repulsion_threshold=0.20, # Increased threshold for broader initial spread ++ boundary_strength=0.06, # Slightly increased boundary repulsion ++ boundary_margin=0.03 ++ ) ++ self.radii = compute_max_radii(self.centers) ++ self.sum_radii = np.sum(self.radii) ++ ++ # Initialize current and best states for Simulated Annealing ++ best_centers = self.centers.copy() ++ best_radii = self.radii.copy() ++ best_sum_radii = self.sum_radii ++ ++ current_centers = self.centers.copy() ++ current_radii = self.radii.copy() ++ current_sum_radii = self.sum_radii ++ ++ total_iterations = 15000 # Increased total iterations for thorough SA search ++ initial_global_perturb_strength_base = 0.04 # Base initial perturbation for more exploration. ++ final_global_perturb_strength = 0.0003 # Slightly lower final for finer tuning. ++ ++ T_initial = 0.2 # Increased initial temperature to accept more "worse" moves initially. ++ T_final = 1e-7 # Even lower final temperature for very greedy behavior at the end. ++ ++ # Counter for progress-sensitive adaptive perturbation strength ++ no_improvement_count = 0 ++ max_no_improvement_steps = 500 # If no improvement for this many steps, boost initial perturb_strength ++ ++ # Use a mutable variable for current initial_global_perturb_strength ++ current_initial_global_perturb_strength = initial_global_perturb_strength_base ++ ++ for iteration in range(total_iterations): ++ # Linearly decay global perturbation strength ++ global_perturb_strength = current_initial_global_perturb_strength * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) ++ ++ # Exponentially decay temperature ++ temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) ++ ++ candidate_centers = current_centers.copy() ++ ++ # Select a circle to perturb using adaptive selection criteria ++ circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) ++ ++ # Determine perturbation strength dynamically for the selected circle ++ effective_perturb_strength = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) ++ ++ # Generate and apply displacement ++ displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) ++ ++ # Evaluate the candidate configuration ++ candidate_radii = compute_max_radii(candidate_centers) ++ candidate_sum_radii = np.sum(candidate_radii) ++ ++ # Simulated Annealing acceptance criteria ++ accepted = False ++ if candidate_sum_radii > current_sum_radii: ++ # Always accept better solutions ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers.copy() ++ current_radii = candidate_radii.copy() ++ accepted = True ++ else: ++ # Accept worse solutions with a probability based on temperature ++ delta = candidate_sum_radii - current_sum_radii # Will be negative or zero ++ acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 ++ ++ if np.random.rand() < acceptance_prob: ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers.copy() ++ current_radii = candidate_radii.copy() ++ accepted = True ++ ++ # Update the globally best solution found so far ++ if current_sum_radii > best_sum_radii: ++ best_sum_radii = current_sum_radii ++ best_centers = current_centers.copy() ++ best_radii = current_radii.copy() ++ no_improvement_count = 0 # Reset counter on new best ++ elif not accepted: # If not accepted and not better ++ no_improvement_count += 1 ++ # Adaptive adjustment: If stuck, temporarily boost perturbation to escape ++ if no_improvement_count > max_no_improvement_steps: ++ current_initial_global_perturb_strength *= 1.2 # Boost initial strength ++ no_improvement_count = 0 # Reset counter ++ ++ return best_centers, best_radii ++ ++def construct_packing(): ++ """ ++ Main function to construct the circle packing. ++ Initializes CirclePacker and runs its packing method. ++ """ ++ packer = CirclePacker(n=26) ++ return packer.pack() + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/main.py new file mode 100644 index 0000000000000000000000000000000000000000..de85906b2b89a4ce9ce2a4d38de2ff69f2b3af19 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/main.py @@ -0,0 +1,287 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using Modular Simulated Annealing local search""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + # Only set changes_made if they weren't already exactly 0 + if radii[i] > 1e-12 or radii[j] > 1e-12: + radii[i] = 0 + radii[j] = 0 + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Asymmetric void adjusted to (0.3, 0.3) for varied initial exploration. + void_center = np.array([0.3, 0.3]) + amplitude = 0.07 # Slightly increased amplitude for a larger initial void. + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) # Ensure centers are within [0,1] square + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _apply_force_directed_relaxation(self, centers_to_relax, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to a set of circle centers. + Circles repel each other and are repelled by boundaries. + """ + n_local = centers_to_relax.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers_to_relax) + + # Circle-circle repulsion + for i in range(n_local): + for j in range(i + 1, n_local): + vec = centers_to_relax[i] - centers_to_relax[j] + dist = np.linalg.norm(vec) + # Increased repulsion threshold to encourage more spacing initially + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n_local): + x, y = centers_to_relax[i] + # Increased boundary strength to push centers closer to edges + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + centers_to_relax += step_size * forces + centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) # Keep centers within bounds + return centers_to_relax + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius and proximity to boundaries. + Smaller circles and those closer to boundaries have a higher chance of being selected. + """ + inverse_radii = 1 / (current_radii + 1e-8) + + # Calculate distance to nearest boundary for each circle + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + + # Exponentially weight circles closer to boundaries + # Reduced scale factor (0.07) to make boundary proximity more influential. + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Combine inverse_radii and boundary proximity to get selection weights + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) + selection_probs = combined_weights / np.sum(combined_weights) + + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation to help them + escape local minima. + """ + max_r = np.max(current_radii) + 1e-8 # Avoid division by zero + relative_radius = current_radii[circle_idx] / max_r + + # Perturbation factor: 1.0 for the largest circle, up to 3.0 for the smallest. + # Increased multiplier (2.0) for more aggressive movement of small circles. + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 + + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing. + """ + self._initialize_centers() + + # Pre-optimization with a short, mild Force-Directed Relaxation stage + self.centers = self._apply_force_directed_relaxation( + self.centers.copy(), + iterations=750, # Increased iterations for F-D + step_size=0.0015, # Slightly increased step size + repulsion_strength=0.012, # Slightly increased repulsion + repulsion_threshold=0.20, # Increased threshold for broader initial spread + boundary_strength=0.06, # Slightly increased boundary repulsion + boundary_margin=0.03 + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + # Initialize current and best states for Simulated Annealing + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + total_iterations = 15000 # Increased total iterations for thorough SA search + initial_global_perturb_strength_base = 0.04 # Base initial perturbation for more exploration. + final_global_perturb_strength = 0.0003 # Slightly lower final for finer tuning. + + T_initial = 0.2 # Increased initial temperature to accept more "worse" moves initially. + T_final = 1e-7 # Even lower final temperature for very greedy behavior at the end. + + # Counter for progress-sensitive adaptive perturbation strength + no_improvement_count = 0 + max_no_improvement_steps = 500 # If no improvement for this many steps, boost initial perturb_strength + + # Use a mutable variable for current initial_global_perturb_strength + current_initial_global_perturb_strength = initial_global_perturb_strength_base + + for iteration in range(total_iterations): + # Linearly decay global perturbation strength + global_perturb_strength = current_initial_global_perturb_strength * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + + # Exponentially decay temperature + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + # Select a circle to perturb using adaptive selection criteria + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + + # Determine perturbation strength dynamically for the selected circle + effective_perturb_strength = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + + # Generate and apply displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the candidate configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + # Always accept better solutions + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + # Accept worse solutions with a probability based on temperature + delta = candidate_sum_radii - current_sum_radii # Will be negative or zero + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update the globally best solution found so far + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset counter on new best + elif not accepted: # If not accepted and not better + no_improvement_count += 1 + # Adaptive adjustment: If stuck, temporarily boost perturbation to escape + if no_improvement_count > max_no_improvement_steps: + current_initial_global_perturb_strength *= 1.2 # Boost initial strength + no_improvement_count = 0 # Reset counter + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePacker and runs its packing method. + """ + packer = CirclePacker(n=26) + return packer.pack() +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/original.py new file mode 100644 index 0000000000000000000000000000000000000000..09bee8261192f3efe418cfd40bc9b2718af1ed4e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/original.py @@ -0,0 +1,159 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Breaking the initial symmetry by using an off-center void at (0.4, 0.2) + # prevents the relaxation from getting stuck in an overly-ordered local optimum. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.06 # The maximum distance to push a circle. Increased to create a larger void. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Iterative Local Search with Greedy Acceptance + # Replace the ineffective force-directed method with a more robust local search. + best_centers = centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + # Parameters for the local search, inspired by prior successful models. + total_iterations = 10000 + initial_perturb_strength = 0.025 + final_perturb_strength = 0.0005 + + for iteration in range(total_iterations): + # Linearly anneal perturbation strength for exploration -> exploitation. + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + candidate_centers = best_centers.copy() + + # Target smaller circles, as they are more likely to be in suboptimal positions. + inverse_radii = 1 / (best_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + circle_idx = np.random.choice(n, p=selection_probs) + + # Apply a random displacement. + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration. + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Greedy acceptance: only accept better solutions. + if candidate_sum_radii > best_sum_radii: + best_sum_radii = candidate_sum_radii + best_centers = candidate_centers.copy() + best_radii = candidate_radii.copy() + + # 6. Return the best configuration found by the local search. + return best_centers, best_radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Vectorized initialization: radii are limited by distance to square borders. + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate. + for _ in range(500): # More iterations for better convergence. + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + # This branch handles cases where radii are already near zero. + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..294e87a0bbf2d2bc259801de93f151d588dfd9d3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_137/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_137/results +Run 1/1 completed in 34.19 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.338109481717179 + public: {'centers_str': ' centers[0] = (0.0648, 0.9358)\n centers[1] = (0.8363, 0.0652)\n centers[2] = (0.6931, 0.0781)\n centers[3] = (0.7779, 0.6317)\n centers[4] = (0.9135, 0.9120)\n centers[5] = (0.4044, 0.3395)\n centers[6] = (0.9484, 0.0982)\n centers[7] = (0.0668, 0.2604)\n centers[8] = (0.3488, 0.6736)\n centers[9] = (0.7323, 0.4766)\n centers[10] = (0.2348, 0.2850)\n centers[11] = (0.3167, 0.0989)\n centers[12] = (0.5741, 0.3416)\n centers[13] = (0.8531, 0.2719)\n centers[14] = (0.4064, 0.2566)\n centers[15] = (0.5465, 0.5798)\n centers[16] = (0.1256, 0.4855)\n centers[17] = (0.6770, 0.7184)\n centers[18] = (0.9109, 0.5002)\n centers[19] = (0.7301, 0.9029)\n centers[20] = (0.1183, 0.0998)\n centers[21] = (0.3669, 0.4696)\n centers[22] = (0.4855, 0.8580)\n centers[23] = (0.8856, 0.7031)\n centers[24] = (0.1372, 0.7487)\n centers[25] = (0.5286, 0.1152)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.338109481717179} + visualization_path: + execution_time_mean: 34.193553399760276 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..34325d73c1a0017657124d80235bbb4207fd82c5 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.338109481717179, + "public": { + "centers_str": " centers[0] = (0.0648, 0.9358)\n centers[1] = (0.8363, 0.0652)\n centers[2] = (0.6931, 0.0781)\n centers[3] = (0.7779, 0.6317)\n centers[4] = (0.9135, 0.9120)\n centers[5] = (0.4044, 0.3395)\n centers[6] = (0.9484, 0.0982)\n centers[7] = (0.0668, 0.2604)\n centers[8] = (0.3488, 0.6736)\n centers[9] = (0.7323, 0.4766)\n centers[10] = (0.2348, 0.2850)\n centers[11] = (0.3167, 0.0989)\n centers[12] = (0.5741, 0.3416)\n centers[13] = (0.8531, 0.2719)\n centers[14] = (0.4064, 0.2566)\n centers[15] = (0.5465, 0.5798)\n centers[16] = (0.1256, 0.4855)\n centers[17] = (0.6770, 0.7184)\n centers[18] = (0.9109, 0.5002)\n centers[19] = (0.7301, 0.9029)\n centers[20] = (0.1183, 0.0998)\n centers[21] = (0.3669, 0.4696)\n centers[22] = (0.4855, 0.8580)\n centers[23] = (0.8856, 0.7031)\n centers[24] = (0.1372, 0.7487)\n centers[25] = (0.5286, 0.1152)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.338109481717179 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_137/results/packing_viz.png", + "execution_time_mean": 34.193553399760276, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad174d002412bb600c2c4bb02d4443b85ddb86e3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_137/rewrite.txt @@ -0,0 +1,278 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using Modular Simulated Annealing local search""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + # Only set changes_made if they weren't already exactly 0 + if radii[i] > 1e-12 or radii[j] > 1e-12: + radii[i] = 0 + radii[j] = 0 + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Asymmetric void adjusted to (0.3, 0.3) for varied initial exploration. + void_center = np.array([0.3, 0.3]) + amplitude = 0.07 # Slightly increased amplitude for a larger initial void. + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) # Ensure centers are within [0,1] square + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _apply_force_directed_relaxation(self, centers_to_relax, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to a set of circle centers. + Circles repel each other and are repelled by boundaries. + """ + n_local = centers_to_relax.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers_to_relax) + + # Circle-circle repulsion + for i in range(n_local): + for j in range(i + 1, n_local): + vec = centers_to_relax[i] - centers_to_relax[j] + dist = np.linalg.norm(vec) + # Increased repulsion threshold to encourage more spacing initially + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n_local): + x, y = centers_to_relax[i] + # Increased boundary strength to push centers closer to edges + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + centers_to_relax += step_size * forces + centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) # Keep centers within bounds + return centers_to_relax + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius and proximity to boundaries. + Smaller circles and those closer to boundaries have a higher chance of being selected. + """ + inverse_radii = 1 / (current_radii + 1e-8) + + # Calculate distance to nearest boundary for each circle + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + + # Exponentially weight circles closer to boundaries + # Reduced scale factor (0.07) to make boundary proximity more influential. + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Combine inverse_radii and boundary proximity to get selection weights + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) + selection_probs = combined_weights / np.sum(combined_weights) + + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation to help them + escape local minima. + """ + max_r = np.max(current_radii) + 1e-8 # Avoid division by zero + relative_radius = current_radii[circle_idx] / max_r + + # Perturbation factor: 1.0 for the largest circle, up to 3.0 for the smallest. + # Increased multiplier (2.0) for more aggressive movement of small circles. + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 + + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing. + """ + self._initialize_centers() + + # Pre-optimization with a short, mild Force-Directed Relaxation stage + self.centers = self._apply_force_directed_relaxation( + self.centers.copy(), + iterations=750, # Increased iterations for F-D + step_size=0.0015, # Slightly increased step size + repulsion_strength=0.012, # Slightly increased repulsion + repulsion_threshold=0.20, # Increased threshold for broader initial spread + boundary_strength=0.06, # Slightly increased boundary repulsion + boundary_margin=0.03 + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + # Initialize current and best states for Simulated Annealing + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + total_iterations = 15000 # Increased total iterations for thorough SA search + initial_global_perturb_strength_base = 0.04 # Base initial perturbation for more exploration. + final_global_perturb_strength = 0.0003 # Slightly lower final for finer tuning. + + T_initial = 0.2 # Increased initial temperature to accept more "worse" moves initially. + T_final = 1e-7 # Even lower final temperature for very greedy behavior at the end. + + # Counter for progress-sensitive adaptive perturbation strength + no_improvement_count = 0 + max_no_improvement_steps = 500 # If no improvement for this many steps, boost initial perturb_strength + + # Use a mutable variable for current initial_global_perturb_strength + current_initial_global_perturb_strength = initial_global_perturb_strength_base + + for iteration in range(total_iterations): + # Linearly decay global perturbation strength + global_perturb_strength = current_initial_global_perturb_strength * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + + # Exponentially decay temperature + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + # Select a circle to perturb using adaptive selection criteria + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + + # Determine perturbation strength dynamically for the selected circle + effective_perturb_strength = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + + # Generate and apply displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the candidate configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + # Always accept better solutions + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + # Accept worse solutions with a probability based on temperature + delta = candidate_sum_radii - current_sum_radii # Will be negative or zero + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update the globally best solution found so far + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset counter on new best + elif not accepted: # If not accepted and not better + no_improvement_count += 1 + # Adaptive adjustment: If stuck, temporarily boost perturbation to escape + if no_improvement_count > max_no_improvement_steps: + current_initial_global_perturb_strength *= 1.2 # Boost initial strength + no_improvement_count = 0 # Reset counter + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePacker and runs its packing method. + """ + packer = CirclePacker(n=26) + return packer.pack() +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca697859b181546d7f87e20033d0e5e0cb0e788b Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..344278fb4657a4cd0181bd9e2d629095f32cd49d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_138/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_138/results +Run 1/1 completed in 26.83 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.196967355915802 + public: {'centers_str': ' centers[0] = (0.3463, 0.4018)\n centers[1] = (0.7465, 0.0535)\n centers[2] = (0.6288, 0.5667)\n centers[3] = (0.5143, 0.0442)\n centers[4] = (0.8909, 0.1282)\n centers[5] = (0.3648, 0.1577)\n centers[6] = (0.4222, 0.0479)\n centers[7] = (0.6434, 0.7438)\n centers[8] = (0.6227, 0.2369)\n centers[9] = (0.8898, 0.3470)\n centers[10] = (0.0583, 0.0572)\n centers[11] = (0.2524, 0.4252)\n centers[12] = (0.3517, 0.3199)\n centers[13] = (0.7354, 0.4924)\n centers[14] = (0.9545, 0.4878)\n centers[15] = (0.1528, 0.6214)\n centers[16] = (0.3751, 0.8396)\n centers[17] = (0.4492, 0.5312)\n centers[18] = (0.9156, 0.9158)\n centers[19] = (0.8952, 0.6253)\n centers[20] = (0.1097, 0.8854)\n centers[21] = (0.5581, 0.9472)\n centers[22] = (0.5977, 0.8384)\n centers[23] = (0.9442, 0.7786)\n centers[24] = (0.7649, 0.7949)\n centers[25] = (0.1461, 0.2406)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.196967355915802} + visualization_path: + execution_time_mean: 26.82969739800319 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..36e656dc4ad5847004d0ce321c22428f427261ea --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.196967355915802, + "public": { + "centers_str": " centers[0] = (0.3463, 0.4018)\n centers[1] = (0.7465, 0.0535)\n centers[2] = (0.6288, 0.5667)\n centers[3] = (0.5143, 0.0442)\n centers[4] = (0.8909, 0.1282)\n centers[5] = (0.3648, 0.1577)\n centers[6] = (0.4222, 0.0479)\n centers[7] = (0.6434, 0.7438)\n centers[8] = (0.6227, 0.2369)\n centers[9] = (0.8898, 0.3470)\n centers[10] = (0.0583, 0.0572)\n centers[11] = (0.2524, 0.4252)\n centers[12] = (0.3517, 0.3199)\n centers[13] = (0.7354, 0.4924)\n centers[14] = (0.9545, 0.4878)\n centers[15] = (0.1528, 0.6214)\n centers[16] = (0.3751, 0.8396)\n centers[17] = (0.4492, 0.5312)\n centers[18] = (0.9156, 0.9158)\n centers[19] = (0.8952, 0.6253)\n centers[20] = (0.1097, 0.8854)\n centers[21] = (0.5581, 0.9472)\n centers[22] = (0.5977, 0.8384)\n centers[23] = (0.9442, 0.7786)\n centers[24] = (0.7649, 0.7949)\n centers[25] = (0.1461, 0.2406)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.196967355915802 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_138/results/packing_viz.png", + "execution_time_mean": 26.82969739800319, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0483f8dcdb52f639c7e81a0d832d0993d08ff72d Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..63613f40dde29470283431b7def3cb8efbb87956 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/edit.diff @@ -0,0 +1,304 @@ +--- a/original.py ++++ b/original.py +@@ -1,277 +1,298 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + + # compute_max_radii remains unchanged as it's a robust evaluation function. + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + + class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Use np.divide with where clause to handle potential division by zero for diff/dists + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = self.centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + ++ # Stagnation detection and escape parameters ++ no_improvement_count = 0 ++ max_no_improvement_steps = 1000 # Iterations without improvement to trigger a boost ++ perturb_boost = 1.0 ++ boost_factor = 4.0 # A strong, but not excessively disruptive, kick ++ boost_decay = 0.95 # Gradual decay of the boost ++ + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + ++ # Check for stagnation and apply a temporary perturbation boost ++ if no_improvement_count >= max_no_improvement_steps: ++ perturb_boost = boost_factor ++ no_improvement_count = 0 # Reset counter after triggering boost ++ + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. +- effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) ++ effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius +- effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) ++ effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + ++ # Decay the perturbation boost so its effect is temporary ++ if perturb_boost > 1.0: ++ perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + +- # If this is the best state found so far, save it ++ # If this is the best state found so far, save it and reset stagnation counter + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() ++ no_improvement_count = 0 ++ else: ++ no_improvement_count += 1 ++ else: ++ # Reject the new state ++ no_improvement_count += 1 + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_local_search( + total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/main.py new file mode 100644 index 0000000000000000000000000000000000000000..32faf10c71aef93ec79e2f49a4765eb2f067e5e9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/main.py @@ -0,0 +1,298 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Use np.divide with where clause to handle potential division by zero for diff/dists + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = self.centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + # Stagnation detection and escape parameters + no_improvement_count = 0 + max_no_improvement_steps = 1000 # Iterations without improvement to trigger a boost + perturb_boost = 1.0 + boost_factor = 4.0 # A strong, but not excessively disruptive, kick + boost_decay = 0.95 # Gradual decay of the boost + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Check for stagnation and apply a temporary perturbation boost + if no_improvement_count >= max_no_improvement_steps: + perturb_boost = boost_factor + no_improvement_count = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it and reset stagnation counter + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + else: + # Reject the new state + no_improvement_count += 1 + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_local_search( + total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/original.py new file mode 100644 index 0000000000000000000000000000000000000000..1a2cd8b239d8260f5d20ce8cae649f37c1ad3c7f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/original.py @@ -0,0 +1,277 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Use np.divide with where clause to handle potential division by zero for diff/dists + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = self.centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_local_search( + total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..0251e8c1cd0cd7f6e6c88e648e6614e100d830cb --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_141/main.py:101: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..72e13d20eb69d60331153616ce179b4f80204ec4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_141/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_141/results +Run 1/1 completed in 33.96 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.2363076272366915 + public: {'centers_str': ' centers[0] = (0.0841, 0.0841)\n centers[1] = (0.4124, 0.0328)\n centers[2] = (0.5190, 0.0897)\n centers[3] = (0.6937, 0.0864)\n centers[4] = (0.8948, 0.1052)\n centers[5] = (0.1127, 0.2794)\n centers[6] = (0.2864, 0.1218)\n centers[7] = (0.4971, 0.2552)\n centers[8] = (0.7254, 0.2397)\n centers[9] = (0.9144, 0.2950)\n centers[10] = (0.0958, 0.5219)\n centers[11] = (0.2766, 0.3784)\n centers[12] = (0.6300, 0.6655)\n centers[13] = (0.7649, 0.5859)\n centers[14] = (0.8978, 0.4821)\n centers[15] = (0.0906, 0.7082)\n centers[16] = (0.3055, 0.6738)\n centers[17] = (0.5302, 0.7146)\n centers[18] = (0.7058, 0.7270)\n centers[19] = (0.8980, 0.6876)\n centers[20] = (0.1105, 0.8905)\n centers[21] = (0.3104, 0.9088)\n centers[22] = (0.5029, 0.8986)\n centers[23] = (0.6971, 0.9071)\n centers[24] = (0.8948, 0.8947)\n centers[25] = (0.5666, 0.4668)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.2363076272366915} + visualization_path: + execution_time_mean: 33.95845269598067 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..70be04cb1ce369458c4f682462392fec2973ca09 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.2363076272366915, + "public": { + "centers_str": " centers[0] = (0.0841, 0.0841)\n centers[1] = (0.4124, 0.0328)\n centers[2] = (0.5190, 0.0897)\n centers[3] = (0.6937, 0.0864)\n centers[4] = (0.8948, 0.1052)\n centers[5] = (0.1127, 0.2794)\n centers[6] = (0.2864, 0.1218)\n centers[7] = (0.4971, 0.2552)\n centers[8] = (0.7254, 0.2397)\n centers[9] = (0.9144, 0.2950)\n centers[10] = (0.0958, 0.5219)\n centers[11] = (0.2766, 0.3784)\n centers[12] = (0.6300, 0.6655)\n centers[13] = (0.7649, 0.5859)\n centers[14] = (0.8978, 0.4821)\n centers[15] = (0.0906, 0.7082)\n centers[16] = (0.3055, 0.6738)\n centers[17] = (0.5302, 0.7146)\n centers[18] = (0.7058, 0.7270)\n centers[19] = (0.8980, 0.6876)\n centers[20] = (0.1105, 0.8905)\n centers[21] = (0.3104, 0.9088)\n centers[22] = (0.5029, 0.8986)\n centers[23] = (0.6971, 0.9071)\n centers[24] = (0.8948, 0.8947)\n centers[25] = (0.5666, 0.4668)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.2363076272366915 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_141/results/packing_viz.png", + "execution_time_mean": 33.95845269598067, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..0e683111cde32da08f554bf6a449557ab1537837 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_141/search_replace.txt @@ -0,0 +1,145 @@ +An analysis of the provided visualization reveals a significant packing inefficiency. The spatial distribution is dominated by a single large, centrally-located circle, which severely constrains the radii of its numerous neighbors, resulting in many small, underdeveloped circles and large pockets of unused space around them. This configuration is a classic example of a deep local optimum where any small adjustment (like shrinking the large circle) leads to a temporary decrease in the total sum of radii, causing the search to stagnate. + +To address this, I will implement a stagnation escape mechanism within the simulated annealing process. This strategy, inspired by Iterated Local Search and adaptive metaheuristics, is designed to "kick" the system out of such unproductive optima. + +The proposed change introduces a `no_improvement_count` that tracks the number of iterations without finding a new best solution. If this count exceeds a threshold, the algorithm is considered stuck. In response, a temporary `perturb_boost` is applied, significantly increasing the perturbation strength for a short period. This boost then decays exponentially over subsequent iterations. This allows for an aggressive, targeted exploration phase to break the existing structure (e.g., shrink the "king" circle) and find a new, more promising region of the solution space, without permanently disrupting the fine-tuning ability of the later, low-temperature stages of the annealing process. + + +stagnation_escape_boost + + +The visualization shows the packing is stuck in a local optimum with one large central circle and many small surrounding ones. To escape this, I'm introducing a stagnation detection mechanism into the simulated annealing loop. If no improvement is found for 1000 iterations, a temporary "perturbation boost" is triggered, multiplying the perturbation strength by 4.0. This boost then decays over subsequent iterations. This "kick" is designed to force the system out of deep local optima and explore more diverse, and hopefully denser, configurations. + + +<<<<<<< SEARCH + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + for iteration in range(total_iterations): +======= + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + # Stagnation detection and escape parameters + no_improvement_count = 0 + max_no_improvement_steps = 1000 # Iterations without improvement to trigger a boost + perturb_boost = 1.0 + boost_factor = 4.0 # A strong, but not excessively disruptive, kick + boost_decay = 0.95 # Gradual decay of the boost + + for iteration in range(total_iterations): +>>>>>>> REPLACE + + +<<<<<<< SEARCH + # Logarithmic decay for temperature and perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() +======= + # Logarithmic decay for temperature and perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Check for stagnation and apply a temporary perturbation boost + if no_improvement_count >= max_no_improvement_steps: + perturb_boost = boost_factor + no_improvement_count = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() +>>>>>>> REPLACE + + +<<<<<<< SEARCH + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +======= + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +>>>>>>> REPLACE + + +<<<<<<< SEARCH + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +======= + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +>>>>>>> REPLACE + + +<<<<<<< SEARCH + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) +======= + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) +>>>>>>> REPLACE + + +<<<<<<< SEARCH + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() +======= + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it and reset stagnation counter + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + else: + # Reject the new state + no_improvement_count += 1 +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8f015ba4e3d976eda5b881910efca78b646c17f1 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..091aad1547806bd45637ed3c7e63a1107b6f5bc4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/edit.diff @@ -0,0 +1,189 @@ +--- a/original.py ++++ b/original.py +@@ -1,142 +1,155 @@ + # EVOLVE-BLOCK-START + import numpy as np ++import math + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +-def initial_centers(n): +- """Generates the asymmetric grid-deformed starting configuration.""" ++def initial_centers(n, void_center): ++ """Generates the grid-deformed starting configuration based on a void center.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + return np.clip(centers, 0.0, 1.0) + +-def jiggle_phase(centers, n): +- """A short, vectorized force-directed relaxation phase to 'jiggle' circles into a better local state.""" +- iters = 15 +- step_size = 0.001 +- repulsion_strength = 0.01 +- boundary_strength = 0.05 +- repulsion_threshold = 0.19 +- boundary_margin = 0.02 +- ++def jiggle_phase(centers, n, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): ++ """A vectorized force-directed relaxation phase to 'jiggle' circles into a better local state.""" + jiggled_centers = centers.copy() + + for _ in range(iters): + diff = jiggled_centers[:, np.newaxis, :] - jiggled_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - jiggled_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, jiggled_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - jiggled_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, jiggled_centers[:, 1] - (1 - boundary_margin)) + + jiggled_centers += step_size * forces + jiggled_centers = np.clip(jiggled_centers, 0.0, 1.0) + + return jiggled_centers + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles using a novel hybrid algorithm +- that alternates between stochastic local search and deterministic force-directed 'jiggling'. ++ Constructs a high-density arrangement of 26 circles using a hybrid ++ Simulated Annealing (SA) and force-directed relaxation approach. + """ + n = 26 + +- centers = initial_centers(n) ++ # 1. Randomized Initial Placement ++ void_center = np.random.uniform(0.3, 0.7, 2) ++ centers = initial_centers(n, void_center) + +- best_centers = jiggle_phase(centers, n) +- best_radii = compute_max_radii(best_centers) +- best_sum_radii = np.sum(best_radii) ++ # 2. Initial Aggressive Relaxation ++ current_centers = jiggle_phase( ++ centers, n, iters=300, step_size=0.002, repulsion_strength=0.02, ++ boundary_strength=0.05, repulsion_threshold=0.19, boundary_margin=0.04 ++ ) ++ current_radii = compute_max_radii(current_centers) ++ current_sum_radii = np.sum(current_radii) + +- total_iterations = 4000 ++ best_centers = current_centers.copy() ++ best_sum_radii = current_sum_radii ++ ++ # 3. Simulated Annealing Main Loop ++ total_iterations = 20000 ++ initial_temp = 0.0005 ++ final_temp = 1e-8 + initial_perturb_strength = 0.03 + final_perturb_strength = 0.0001 + +- current_radii = best_radii.copy() +- + for iteration in range(total_iterations): + progress = iteration / total_iterations +- perturb_strength = initial_perturb_strength * (1 - progress) + final_perturb_strength * progress ++ temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) ++ perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + +- candidate_centers = best_centers.copy() ++ candidate_centers = current_centers.copy() + + inverse_radii = 1.0 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(n, p=selection_probs) + + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + +- jiggled_centers = jiggle_phase(candidate_centers, n) +- +- candidate_radii = compute_max_radii(jiggled_centers) ++ candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + +- if candidate_sum_radii > best_sum_radii: +- best_sum_radii = candidate_sum_radii +- best_centers = jiggled_centers ++ delta_E = candidate_sum_radii - current_sum_radii ++ if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): ++ current_centers = candidate_centers + current_radii = candidate_radii ++ current_sum_radii = candidate_sum_radii + +- final_radii = compute_max_radii(best_centers) +- return best_centers, final_radii ++ if current_sum_radii > best_sum_radii: ++ best_sum_radii = current_sum_radii ++ best_centers = current_centers.copy() ++ ++ # 4. Final Gentle Polish ++ final_centers = jiggle_phase( ++ best_centers, n, iters=150, step_size=0.0001, repulsion_strength=0.001, ++ boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 ++ ) ++ final_radii = compute_max_radii(final_centers) ++ ++ return final_centers, final_radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/main.py new file mode 100644 index 0000000000000000000000000000000000000000..d9b6209dad116d618cc20d2a61dcf714a692150d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/main.py @@ -0,0 +1,155 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +def initial_centers(n, void_center): + """Generates the grid-deformed starting configuration based on a void center.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + return np.clip(centers, 0.0, 1.0) + +def jiggle_phase(centers, n, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """A vectorized force-directed relaxation phase to 'jiggle' circles into a better local state.""" + jiggled_centers = centers.copy() + + for _ in range(iters): + diff = jiggled_centers[:, np.newaxis, :] - jiggled_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - jiggled_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, jiggled_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - jiggled_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, jiggled_centers[:, 1] - (1 - boundary_margin)) + + jiggled_centers += step_size * forces + jiggled_centers = np.clip(jiggled_centers, 0.0, 1.0) + + return jiggled_centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a hybrid + Simulated Annealing (SA) and force-directed relaxation approach. + """ + n = 26 + + # 1. Randomized Initial Placement + void_center = np.random.uniform(0.3, 0.7, 2) + centers = initial_centers(n, void_center) + + # 2. Initial Aggressive Relaxation + current_centers = jiggle_phase( + centers, n, iters=300, step_size=0.002, repulsion_strength=0.02, + boundary_strength=0.05, repulsion_threshold=0.19, boundary_margin=0.04 + ) + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_sum_radii = current_sum_radii + + # 3. Simulated Annealing Main Loop + total_iterations = 20000 + initial_temp = 0.0005 + final_temp = 1e-8 + initial_perturb_strength = 0.03 + final_perturb_strength = 0.0001 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + inverse_radii = 1.0 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(n, p=selection_probs) + + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + + # 4. Final Gentle Polish + final_centers = jiggle_phase( + best_centers, n, iters=150, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 + ) + final_radii = compute_max_radii(final_centers) + + return final_centers, final_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/original.py new file mode 100644 index 0000000000000000000000000000000000000000..aba957be4c525e7b42f1034e33561f9c82e4ca01 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/original.py @@ -0,0 +1,142 @@ +# EVOLVE-BLOCK-START +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +def initial_centers(n): + """Generates the asymmetric grid-deformed starting configuration.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + return np.clip(centers, 0.0, 1.0) + +def jiggle_phase(centers, n): + """A short, vectorized force-directed relaxation phase to 'jiggle' circles into a better local state.""" + iters = 15 + step_size = 0.001 + repulsion_strength = 0.01 + boundary_strength = 0.05 + repulsion_threshold = 0.19 + boundary_margin = 0.02 + + jiggled_centers = centers.copy() + + for _ in range(iters): + diff = jiggled_centers[:, np.newaxis, :] - jiggled_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - jiggled_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, jiggled_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - jiggled_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, jiggled_centers[:, 1] - (1 - boundary_margin)) + + jiggled_centers += step_size * forces + jiggled_centers = np.clip(jiggled_centers, 0.0, 1.0) + + return jiggled_centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a novel hybrid algorithm + that alternates between stochastic local search and deterministic force-directed 'jiggling'. + """ + n = 26 + + centers = initial_centers(n) + + best_centers = jiggle_phase(centers, n) + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + total_iterations = 4000 + initial_perturb_strength = 0.03 + final_perturb_strength = 0.0001 + + current_radii = best_radii.copy() + + for iteration in range(total_iterations): + progress = iteration / total_iterations + perturb_strength = initial_perturb_strength * (1 - progress) + final_perturb_strength * progress + + candidate_centers = best_centers.copy() + + inverse_radii = 1.0 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(n, p=selection_probs) + + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + jiggled_centers = jiggle_phase(candidate_centers, n) + + candidate_radii = compute_max_radii(jiggled_centers) + candidate_sum_radii = np.sum(candidate_radii) + + if candidate_sum_radii > best_sum_radii: + best_sum_radii = candidate_sum_radii + best_centers = jiggled_centers + current_radii = candidate_radii + + final_radii = compute_max_radii(best_centers) + return best_centers, final_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..3d6c2d3a9effbe534a73f028d48159b988b2d0c8 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_142/main.py:68: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..60c0382ce162850c6ab1f85891d2db657985014a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_142/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_142/results +Run 1/1 completed in 42.38 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.081440003918559 + public: {'centers_str': ' centers[0] = (0.0923, 0.0924)\n centers[1] = (0.2486, 0.0662)\n centers[2] = (0.4968, 0.0745)\n centers[3] = (0.6970, 0.0949)\n centers[4] = (0.8959, 0.1042)\n centers[5] = (0.1193, 0.3022)\n centers[6] = (0.3451, 0.2059)\n centers[7] = (0.5447, 0.1726)\n centers[8] = (0.7001, 0.2633)\n centers[9] = (0.9032, 0.3060)\n centers[10] = (0.0927, 0.5126)\n centers[11] = (0.2768, 0.5616)\n centers[12] = (0.4721, 0.3700)\n centers[13] = (0.7283, 0.4315)\n centers[14] = (0.9167, 0.5035)\n centers[15] = (0.0851, 0.6648)\n centers[16] = (0.2755, 0.7675)\n centers[17] = (0.5501, 0.7518)\n centers[18] = (0.7121, 0.6961)\n centers[19] = (0.8993, 0.6867)\n centers[20] = (0.1103, 0.8897)\n centers[21] = (0.3338, 0.9261)\n centers[22] = (0.4938, 0.9134)\n centers[23] = (0.6883, 0.8907)\n centers[24] = (0.8988, 0.8904)\n centers[25] = (0.4121, 0.6095)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.081440003918559} + visualization_path: + execution_time_mean: 42.377560652792454 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..0a25cbb2489bbbe60204da29e536615a5493da33 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.081440003918559, + "public": { + "centers_str": " centers[0] = (0.0923, 0.0924)\n centers[1] = (0.2486, 0.0662)\n centers[2] = (0.4968, 0.0745)\n centers[3] = (0.6970, 0.0949)\n centers[4] = (0.8959, 0.1042)\n centers[5] = (0.1193, 0.3022)\n centers[6] = (0.3451, 0.2059)\n centers[7] = (0.5447, 0.1726)\n centers[8] = (0.7001, 0.2633)\n centers[9] = (0.9032, 0.3060)\n centers[10] = (0.0927, 0.5126)\n centers[11] = (0.2768, 0.5616)\n centers[12] = (0.4721, 0.3700)\n centers[13] = (0.7283, 0.4315)\n centers[14] = (0.9167, 0.5035)\n centers[15] = (0.0851, 0.6648)\n centers[16] = (0.2755, 0.7675)\n centers[17] = (0.5501, 0.7518)\n centers[18] = (0.7121, 0.6961)\n centers[19] = (0.8993, 0.6867)\n centers[20] = (0.1103, 0.8897)\n centers[21] = (0.3338, 0.9261)\n centers[22] = (0.4938, 0.9134)\n centers[23] = (0.6883, 0.8907)\n centers[24] = (0.8988, 0.8904)\n centers[25] = (0.4121, 0.6095)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.081440003918559 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_142/results/packing_viz.png", + "execution_time_mean": 42.377560652792454, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..48363037f5964287f1de8666c3d0ca6f536dd9be --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_142/search_replace.txt @@ -0,0 +1,240 @@ +Based on my analysis of the visual representation and the provided code, the current algorithm is trapped in a local optimum. The arrangement is too grid-like, with significant unused space, indicating the search method is not effectively exploring the solution space. The core issue is the flawed "perturb-and-jiggle" greedy search, which prevents the system from making exploratory moves that are necessary to escape suboptimal configurations. + +I propose a complete overhaul of the optimization strategy, replacing the current method with a robust three-phase hybrid algorithm inspired by previously successful approaches. This involves reintroducing Simulated Annealing (SA) for its ability to escape local optima, and using the `jiggle` (force-relaxation) phase more strategically for pre-processing and post-processing, rather than in every step. + +My changes are as follows: +1. **Import `math`**: Required for the SA calculations. +2. **Parameterize `initial_centers`**: Allows for randomized starting configurations. +3. **Parameterize `jiggle_phase`**: Converts the function into a flexible relaxation tool. +4. **Rewrite `construct_packing`**: Implements a powerful three-phase SA algorithm: initial randomized placement and aggressive relaxation, a long SA search for global optimization, and a final gentle relaxation for polishing. + +This new structure directly addresses the observed stagnation by enabling a much more thorough and effective search. + + +import_math + + +Import the `math` library, which is required for the exponential decay and acceptance probability calculations in the new Simulated Annealing implementation. + + +<<<<<<< SEARCH +import numpy as np + +def compute_max_radii(centers): +======= +import numpy as np +import math + +def compute_max_radii(centers): +>>>>>>> REPLACE + + +parameterize_initial_placement + + +Modify the `initial_centers` function to accept `void_center` as a parameter. This decouples the function from a hardcoded value and allows the main packing algorithm to use randomized starting positions, which is crucial for exploring different regions of the solution space. The docstring is also updated. + + +<<<<<<< SEARCH +def initial_centers(n): + """Generates the asymmetric grid-deformed starting configuration.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + return np.clip(centers, 0.0, 1.0) +======= +def initial_centers(n, void_center): + """Generates the grid-deformed starting configuration based on a void center.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + return np.clip(centers, 0.0, 1.0) +>>>>>>> REPLACE + + +parameterize_jiggle_phase + + +Parameterize the `jiggle_phase` function to accept `iters`, `step_size`, and other force-related parameters. This transforms it from a fixed "jiggle" into a flexible force-directed relaxation tool that can be used for both an aggressive initial settling and a gentle final polish. + + +<<<<<<< SEARCH +def jiggle_phase(centers, n): + """A short, vectorized force-directed relaxation phase to 'jiggle' circles into a better local state.""" + iters = 15 + step_size = 0.001 + repulsion_strength = 0.01 + boundary_strength = 0.05 + repulsion_threshold = 0.19 + boundary_margin = 0.02 + + jiggled_centers = centers.copy() + + for _ in range(iters): +======= +def jiggle_phase(centers, n, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """A vectorized force-directed relaxation phase to 'jiggle' circles into a better local state.""" + jiggled_centers = centers.copy() + + for _ in range(iters): +>>>>>>> REPLACE + + +implement_hybrid_sa + + +The core of the improvement: I'm replacing the flawed greedy search with a robust, three-phase hybrid algorithm. +1. **Randomized Initialization**: Uses the newly parameterized `initial_centers` with a random void to start from different points in the search space. +2. **Simulated Annealing (SA)**: A long SA phase replaces the inefficient "perturb-jiggle" loop. It uses a standard Metropolis-Hastings criterion to escape local optima, which was the main failing of the previous version as seen in the grid-like visual result. The number of iterations is significantly increased. +3. **Phased Relaxation**: The newly parameterized `jiggle_phase` is used for an aggressive initial relaxation and a gentle final polish, a structure that proved successful in prior high-scoring programs. This removes the counter-productive jiggle from inside the main optimization loop. + + +<<<<<<< SEARCH +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a novel hybrid algorithm + that alternates between stochastic local search and deterministic force-directed 'jiggling'. + """ + n = 26 + + centers = initial_centers(n) + + best_centers = jiggle_phase(centers, n) + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + total_iterations = 4000 + initial_perturb_strength = 0.03 + final_perturb_strength = 0.0001 + + current_radii = best_radii.copy() + + for iteration in range(total_iterations): + progress = iteration / total_iterations + perturb_strength = initial_perturb_strength * (1 - progress) + final_perturb_strength * progress + + candidate_centers = best_centers.copy() + + inverse_radii = 1.0 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(n, p=selection_probs) + + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + jiggled_centers = jiggle_phase(candidate_centers, n) + + candidate_radii = compute_max_radii(jiggled_centers) + candidate_sum_radii = np.sum(candidate_radii) + + if candidate_sum_radii > best_sum_radii: + best_sum_radii = candidate_sum_radii + best_centers = jiggled_centers + current_radii = candidate_radii + + final_radii = compute_max_radii(best_centers) + return best_centers, final_radii +======= +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a hybrid + Simulated Annealing (SA) and force-directed relaxation approach. + """ + n = 26 + + # 1. Randomized Initial Placement + void_center = np.random.uniform(0.3, 0.7, 2) + centers = initial_centers(n, void_center) + + # 2. Initial Aggressive Relaxation + current_centers = jiggle_phase( + centers, n, iters=300, step_size=0.002, repulsion_strength=0.02, + boundary_strength=0.05, repulsion_threshold=0.19, boundary_margin=0.04 + ) + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_sum_radii = current_sum_radii + + # 3. Simulated Annealing Main Loop + total_iterations = 20000 + initial_temp = 0.0005 + final_temp = 1e-8 + initial_perturb_strength = 0.03 + final_perturb_strength = 0.0001 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + inverse_radii = 1.0 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(n, p=selection_probs) + + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + + # 4. Final Gentle Polish + final_centers = jiggle_phase( + best_centers, n, iters=150, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 + ) + final_radii = compute_max_radii(final_centers) + + return final_centers, final_radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2dba760bac62f9f8edeeee0c205605e1e71dcb4c Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..9d31c55f77be1a6678c3606248874161c9c8b37a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_144/main.py:93: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..62068ae4d36652f1a1dee4b50880a3a295cc662f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_144/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_144/results +Run 1/1 completed in 40.46 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.146387287366115 + public: {'centers_str': ' centers[0] = (0.0776, 0.0776)\n centers[1] = (0.2721, 0.1218)\n centers[2] = (0.5112, 0.0527)\n centers[3] = (0.6762, 0.1292)\n centers[4] = (0.9021, 0.0980)\n centers[5] = (0.1001, 0.2619)\n centers[6] = (0.3207, 0.3700)\n centers[7] = (0.4021, 0.1389)\n centers[8] = (0.7761, 0.2498)\n centers[9] = (0.9283, 0.3279)\n centers[10] = (0.0856, 0.4345)\n centers[11] = (0.2533, 0.5694)\n centers[12] = (0.6021, 0.6337)\n centers[13] = (0.7311, 0.5276)\n centers[14] = (0.9017, 0.4959)\n centers[15] = (0.0987, 0.6993)\n centers[16] = (0.2992, 0.7039)\n centers[17] = (0.4968, 0.7128)\n centers[18] = (0.6944, 0.7007)\n centers[19] = (0.8981, 0.6963)\n centers[20] = (0.1014, 0.8990)\n centers[21] = (0.2997, 0.9029)\n centers[22] = (0.5084, 0.9042)\n centers[23] = (0.7032, 0.9012)\n centers[24] = (0.9010, 0.8991)\n centers[25] = (0.5483, 0.3561)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.146387287366115} + visualization_path: + execution_time_mean: 40.46212570788339 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..d2748f80ee29810d5edc24c2ba09412c907ea659 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.146387287366115, + "public": { + "centers_str": " centers[0] = (0.0776, 0.0776)\n centers[1] = (0.2721, 0.1218)\n centers[2] = (0.5112, 0.0527)\n centers[3] = (0.6762, 0.1292)\n centers[4] = (0.9021, 0.0980)\n centers[5] = (0.1001, 0.2619)\n centers[6] = (0.3207, 0.3700)\n centers[7] = (0.4021, 0.1389)\n centers[8] = (0.7761, 0.2498)\n centers[9] = (0.9283, 0.3279)\n centers[10] = (0.0856, 0.4345)\n centers[11] = (0.2533, 0.5694)\n centers[12] = (0.6021, 0.6337)\n centers[13] = (0.7311, 0.5276)\n centers[14] = (0.9017, 0.4959)\n centers[15] = (0.0987, 0.6993)\n centers[16] = (0.2992, 0.7039)\n centers[17] = (0.4968, 0.7128)\n centers[18] = (0.6944, 0.7007)\n centers[19] = (0.8981, 0.6963)\n centers[20] = (0.1014, 0.8990)\n centers[21] = (0.2997, 0.9029)\n centers[22] = (0.5084, 0.9042)\n centers[23] = (0.7032, 0.9012)\n centers[24] = (0.9010, 0.8991)\n centers[25] = (0.5483, 0.3561)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.146387287366115 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_144/results/packing_viz.png", + "execution_time_mean": 40.46212570788339, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..112ad07c2978600f1944bf7077d2e0409b524e3c Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..43fe43dbabd9e14a942a97c096a1ad0e68ef6bb3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/edit.diff @@ -0,0 +1,360 @@ +--- a/original.py ++++ b/original.py +@@ -1,163 +1,250 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles using Simulated Annealing local search""" ++"""Constructor-based circle packing for n=26 circles using a Hybrid Force-Directed Relaxation and Adaptive Simulated Annealing search""" + + import numpy as np + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + +- for _ in range(500): # Increased iterations for more thorough convergence ++ for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True +- else: ++ elif radii[i] > 0 or radii[j] > 0: + radii[i] = 0 + radii[j] = 0 +- +- # Note: No need for a second 'changes_made = True' here, as the condition +- # `if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12:` handles it for non-zero changes. +- # For sum_r <= 1e-12, setting to zero is a change. +- if sum_r <= 1e-12: + changes_made = True + + if not changes_made: + break + + return radii + +-def construct_packing(): +- """ +- Constructs a high-density arrangement of 26 circles using an iterative +- local search algorithm with targeted perturbations and Simulated Annealing +- acceptance, starting from an asymmetric Gaussian-deformed grid. +- +- Returns: +- Tuple of (centers, radii) +- centers: np.array of shape (26, 2) with (x, y) coordinates +- radii: np.array of shape (26) with radius of each circle +- """ +- n = 26 +- +- # 1. Initial Grid Generation (from the high-scoring prior program) +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T +- +- # Asymmetric void to break symmetry and provide a starting point for rearrangement +- void_center = np.array([0.4, 0.2]) +- amplitude = 0.06 # Amplitude from the high-scoring prior +- sigma = 0.15 +- +- displacements = base_centers_25 - void_center +- distances = np.linalg.norm(displacements, axis=1) +- mask = distances > 1e-9 +- +- push_magnitudes = np.zeros(25) +- push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) +- +- if np.any(mask): +- displacements[mask] /= distances[mask, np.newaxis] +- +- initial_centers = np.zeros((n, 2)) +- initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- initial_centers[25] = void_center +- initial_centers = np.clip(initial_centers, 0.0, 1.0) +- +- # 2. Iterative Local Search with Simulated Annealing +- best_centers = initial_centers.copy() +- best_radii = compute_max_radii(best_centers) +- best_sum_radii = np.sum(best_radii) +- +- current_centers = initial_centers.copy() +- current_radii = best_radii.copy() # Initialize current state with initial best +- current_sum_radii = best_sum_radii +- +- total_iterations = 10000 # Increased iterations for SA +- initial_perturb_strength = 0.025 # Slightly increased for more initial exploration +- final_perturb_strength = 0.0005 +- +- # Simulated Annealing parameters +- T_initial = 0.05 +- T_final = 1e-5 # Very low final temperature for near-greedy at the end +- +- for iteration in range(total_iterations): +- # Linearly decay perturbation strength +- perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) +- +- # Exponentially decay temperature +- # Using a small epsilon to prevent (0/0) issues at iteration 0 if T_final was 0 +- temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) +- +- candidate_centers = current_centers.copy() +- +- # Target circles that are currently small (more likely to be stuck). +- # Use current_radii for selection to guide from the current state. +- inverse_radii = 1 / (current_radii + 1e-8) +- selection_probs = inverse_radii / np.sum(inverse_radii) +- circle_idx = np.random.choice(n, p=selection_probs) +- +- # Generate a random displacement +- displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) +- candidate_centers[circle_idx] += displacement +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +- +- candidate_radii = compute_max_radii(candidate_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- # Simulated Annealing acceptance criteria +- if candidate_sum_radii > current_sum_radii: +- # Always accept better solutions +- current_sum_radii = candidate_sum_radii +- current_centers = candidate_centers.copy() +- current_radii = candidate_radii.copy() +- else: +- # Accept worse solutions with a probability based on temperature +- delta = candidate_sum_radii - current_sum_radii # This will be negative or zero +- acceptance_prob = np.exp(delta / temperature) +- if np.random.rand() < acceptance_prob: ++class CirclePacker: ++ """ ++ Encapsulates the logic for constructing a high-density arrangement of circles ++ using an asymmetric grid initialization, a pre-optimization force-directed ++ relaxation, and a Simulated Annealing local search with adaptive perturbations. ++ """ ++ def __init__(self, n): ++ self.n = n ++ self.centers = np.zeros((n, 2)) ++ self.radii = np.zeros(n) ++ self.sum_radii = 0.0 ++ ++ def _initialize_centers(self): ++ """ ++ Initializes circle centers using a Gaussian-deformed grid for 25 circles ++ and places the 26th in an asymmetric void. ++ """ ++ x_coords = np.linspace(0.1, 0.9, 5) ++ y_coords = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords, y_coords) ++ base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T ++ ++ # Use the same asymmetric starting point as successful previous models ++ void_center = np.array([0.4, 0.2]) ++ amplitude = 0.06 ++ sigma = 0.15 ++ ++ displacements = base_centers_25 - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ mask = distances > 1e-9 ++ ++ push_magnitudes = np.zeros(25) ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ ++ if np.any(mask): ++ displacements[mask] /= distances[mask, np.newaxis] ++ ++ self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ self.centers[25] = void_center ++ self.centers = np.clip(self.centers, 0.0, 1.0) ++ self.radii = compute_max_radii(self.centers) ++ self.sum_radii = np.sum(self.radii) ++ ++ def _apply_force_directed_relaxation(self, centers_to_relax, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): ++ """ ++ Applies an aggressive force-directed relaxation algorithm to shake the initial grid. ++ """ ++ n_local = centers_to_relax.shape[0] ++ for _ in range(iterations): ++ forces = np.zeros_like(centers_to_relax) ++ ++ # Circle-circle repulsion ++ for i in range(n_local): ++ for j in range(i + 1, n_local): ++ vec = centers_to_relax[i] - centers_to_relax[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n_local): ++ x, y = centers_to_relax[i] ++ if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers_to_relax += step_size * forces ++ centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) ++ return centers_to_relax ++ ++ def _select_circle_for_perturbation(self, current_radii, current_centers): ++ """ ++ Selects a circle to perturb based on its inverse radius and proximity to boundaries. ++ """ ++ inverse_radii = 1 / (current_radii + 1e-8) ++ dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], ++ current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) ++ # More sensitive to boundary proximity to encourage edge/corner optimization ++ boundary_proximity_weight = np.exp(-dist_to_nearest_boundary / 0.05) ++ ++ combined_weights = inverse_radii * (1 + boundary_proximity_weight) ++ selection_probs = combined_weights / np.sum(combined_weights) ++ ++ circle_idx = np.random.choice(self.n, p=selection_probs) ++ return circle_idx ++ ++ def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): ++ """ ++ Calculates an adaptive perturbation strength. Smaller circles get a bigger push. ++ """ ++ max_r = np.max(current_radii) + 1e-8 ++ relative_radius = current_radii[circle_idx] / max_r ++ # Increase multiplier to 2.5 for more aggressive movement of small circles ++ perturb_factor = 1.0 + (1.0 - relative_radius) * 2.5 ++ ++ return global_perturb_strength * perturb_factor ++ ++ def pack(self): ++ """ ++ Executes the full packing process: initialization, pre-optimization, ++ and Simulated Annealing. ++ """ ++ self._initialize_centers() ++ ++ # Pre-optimization with an aggressive Force-Directed Relaxation stage to break the grid ++ self.centers = self._apply_force_directed_relaxation( ++ self.centers.copy(), ++ iterations=800, ++ step_size=0.002, ++ repulsion_strength=0.015, ++ repulsion_threshold=0.22, ++ boundary_strength=0.08, ++ boundary_margin=0.04 ++ ) ++ self.radii = compute_max_radii(self.centers) ++ self.sum_radii = np.sum(self.radii) ++ ++ best_centers = self.centers.copy() ++ best_radii = self.radii.copy() ++ best_sum_radii = self.sum_radii ++ ++ current_centers = self.centers.copy() ++ current_radii = self.radii.copy() ++ current_sum_radii = self.sum_radii ++ ++ total_iterations = 18000 ++ initial_global_perturb_strength_base = 0.05 # Higher initial perturbation ++ final_global_perturb_strength = 0.0002 ++ ++ T_initial = 0.25 # Much higher initial temperature for extensive exploration ++ T_final = 1e-7 ++ ++ no_improvement_count = 0 ++ max_no_improvement_steps = 600 ++ current_initial_global_perturb_strength = initial_global_perturb_strength_base ++ ++ for iteration in range(total_iterations): ++ # Schedules for perturbation and temperature ++ global_perturb_strength = current_initial_global_perturb_strength * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) ++ temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) ++ ++ candidate_centers = current_centers.copy() ++ ++ circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) ++ effective_perturb_strength = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) ++ ++ displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) ++ ++ candidate_radii = compute_max_radii(candidate_centers) ++ candidate_sum_radii = np.sum(candidate_radii) ++ ++ # SA acceptance criteria ++ accepted = False ++ if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() +- +- # Keep track of the globally best solution found so far +- if current_sum_radii > best_sum_radii: +- best_sum_radii = current_sum_radii +- best_centers = current_centers.copy() +- best_radii = current_radii.copy() +- +- return best_centers, best_radii ++ accepted = True ++ else: ++ delta = candidate_sum_radii - current_sum_radii ++ acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 ++ if np.random.rand() < acceptance_prob: ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers.copy() ++ current_radii = candidate_radii.copy() ++ accepted = True ++ ++ # Update best solution and check for stagnation ++ if current_sum_radii > best_sum_radii: ++ best_sum_radii = current_sum_radii ++ best_centers = current_centers.copy() ++ best_radii = current_radii.copy() ++ no_improvement_count = 0 ++ else: ++ no_improvement_count += 1 ++ # Stagnation escape: temporarily boost perturbation ++ if no_improvement_count > max_no_improvement_steps: ++ current_initial_global_perturb_strength *= 1.25 # Stronger boost ++ no_improvement_count = 0 # Reset counter ++ ++ return best_centers, best_radii ++ ++def construct_packing(): ++ """ ++ Main function to construct the circle packing. ++ """ ++ packer = CirclePacker(n=26) ++ return packer.pack() + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/main.py new file mode 100644 index 0000000000000000000000000000000000000000..36a0ef59d789a88918afe5a9f0196f435001c826 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/main.py @@ -0,0 +1,250 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using a Hybrid Force-Directed Relaxation and Adaptive Simulated Annealing search""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i] = 0 + radii[j] = 0 + changes_made = True + + if not changes_made: + break + + return radii + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Use the same asymmetric starting point as successful previous models + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _apply_force_directed_relaxation(self, centers_to_relax, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies an aggressive force-directed relaxation algorithm to shake the initial grid. + """ + n_local = centers_to_relax.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers_to_relax) + + # Circle-circle repulsion + for i in range(n_local): + for j in range(i + 1, n_local): + vec = centers_to_relax[i] - centers_to_relax[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n_local): + x, y = centers_to_relax[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + centers_to_relax += step_size * forces + centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) + return centers_to_relax + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius and proximity to boundaries. + """ + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + # More sensitive to boundary proximity to encourage edge/corner optimization + boundary_proximity_weight = np.exp(-dist_to_nearest_boundary / 0.05) + + combined_weights = inverse_radii * (1 + boundary_proximity_weight) + selection_probs = combined_weights / np.sum(combined_weights) + + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength. Smaller circles get a bigger push. + """ + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + # Increase multiplier to 2.5 for more aggressive movement of small circles + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.5 + + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing. + """ + self._initialize_centers() + + # Pre-optimization with an aggressive Force-Directed Relaxation stage to break the grid + self.centers = self._apply_force_directed_relaxation( + self.centers.copy(), + iterations=800, + step_size=0.002, + repulsion_strength=0.015, + repulsion_threshold=0.22, + boundary_strength=0.08, + boundary_margin=0.04 + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + total_iterations = 18000 + initial_global_perturb_strength_base = 0.05 # Higher initial perturbation + final_global_perturb_strength = 0.0002 + + T_initial = 0.25 # Much higher initial temperature for extensive exploration + T_final = 1e-7 + + no_improvement_count = 0 + max_no_improvement_steps = 600 + current_initial_global_perturb_strength = initial_global_perturb_strength_base + + for iteration in range(total_iterations): + # Schedules for perturbation and temperature + global_perturb_strength = current_initial_global_perturb_strength * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + effective_perturb_strength = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # SA acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + delta = candidate_sum_radii - current_sum_radii + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and check for stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + # Stagnation escape: temporarily boost perturbation + if no_improvement_count > max_no_improvement_steps: + current_initial_global_perturb_strength *= 1.25 # Stronger boost + no_improvement_count = 0 # Reset counter + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + """ + packer = CirclePacker(n=26) + return packer.pack() +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/original.py new file mode 100644 index 0000000000000000000000000000000000000000..6d06d4a3e831c6df6e876f0fbd3979a0cb9a01fb --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/original.py @@ -0,0 +1,163 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using Simulated Annealing local search""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: + radii[i] = 0 + radii[j] = 0 + + # Note: No need for a second 'changes_made = True' here, as the condition + # `if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12:` handles it for non-zero changes. + # For sum_r <= 1e-12, setting to zero is a change. + if sum_r <= 1e-12: + changes_made = True + + if not changes_made: + break + + return radii + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using an iterative + local search algorithm with targeted perturbations and Simulated Annealing + acceptance, starting from an asymmetric Gaussian-deformed grid. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Initial Grid Generation (from the high-scoring prior program) + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Asymmetric void to break symmetry and provide a starting point for rearrangement + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 # Amplitude from the high-scoring prior + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + initial_centers = np.clip(initial_centers, 0.0, 1.0) + + # 2. Iterative Local Search with Simulated Annealing + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = initial_centers.copy() + current_radii = best_radii.copy() # Initialize current state with initial best + current_sum_radii = best_sum_radii + + total_iterations = 10000 # Increased iterations for SA + initial_perturb_strength = 0.025 # Slightly increased for more initial exploration + final_perturb_strength = 0.0005 + + # Simulated Annealing parameters + T_initial = 0.05 + T_final = 1e-5 # Very low final temperature for near-greedy at the end + + for iteration in range(total_iterations): + # Linearly decay perturbation strength + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + # Exponentially decay temperature + # Using a small epsilon to prevent (0/0) issues at iteration 0 if T_final was 0 + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + # Target circles that are currently small (more likely to be stuck). + # Use current_radii for selection to guide from the current state. + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + if candidate_sum_radii > current_sum_radii: + # Always accept better solutions + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + else: + # Accept worse solutions with a probability based on temperature + delta = candidate_sum_radii - current_sum_radii # This will be negative or zero + acceptance_prob = np.exp(delta / temperature) + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + + # Keep track of the globally best solution found so far + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..c0f42fa52cfac8d0af66f188e603abbc87ccc8f6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_145/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_145/results +Run 1/1 completed in 39.16 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.228192568862337 + public: {'centers_str': ' centers[0] = (0.1325, 0.2304)\n centers[1] = (0.3236, 0.6202)\n centers[2] = (0.3817, 0.2818)\n centers[3] = (0.7364, 0.4744)\n centers[4] = (0.8642, 0.8773)\n centers[5] = (0.5643, 0.3795)\n centers[6] = (0.0723, 0.0724)\n centers[7] = (0.4521, 0.9055)\n centers[8] = (0.9439, 0.1494)\n centers[9] = (0.0859, 0.7088)\n centers[10] = (0.0974, 0.9071)\n centers[11] = (0.2175, 0.3350)\n centers[12] = (0.1414, 0.5196)\n centers[13] = (0.4270, 0.0482)\n centers[14] = (0.2604, 0.1198)\n centers[15] = (0.3453, 0.4666)\n centers[16] = (0.2468, 0.6714)\n centers[17] = (0.8564, 0.2816)\n centers[18] = (0.0658, 0.3146)\n centers[19] = (0.2848, 0.8493)\n centers[20] = (0.5876, 0.1557)\n centers[21] = (0.9093, 0.4304)\n centers[22] = (0.5509, 0.6373)\n centers[23] = (0.6287, 0.8991)\n centers[24] = (0.8732, 0.6288)\n centers[25] = (0.8186, 0.1011)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.228192568862337} + visualization_path: + execution_time_mean: 39.158950897865 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..0ce30993a513afaa5098b92ab85e539d027ae4c8 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.228192568862337, + "public": { + "centers_str": " centers[0] = (0.1325, 0.2304)\n centers[1] = (0.3236, 0.6202)\n centers[2] = (0.3817, 0.2818)\n centers[3] = (0.7364, 0.4744)\n centers[4] = (0.8642, 0.8773)\n centers[5] = (0.5643, 0.3795)\n centers[6] = (0.0723, 0.0724)\n centers[7] = (0.4521, 0.9055)\n centers[8] = (0.9439, 0.1494)\n centers[9] = (0.0859, 0.7088)\n centers[10] = (0.0974, 0.9071)\n centers[11] = (0.2175, 0.3350)\n centers[12] = (0.1414, 0.5196)\n centers[13] = (0.4270, 0.0482)\n centers[14] = (0.2604, 0.1198)\n centers[15] = (0.3453, 0.4666)\n centers[16] = (0.2468, 0.6714)\n centers[17] = (0.8564, 0.2816)\n centers[18] = (0.0658, 0.3146)\n centers[19] = (0.2848, 0.8493)\n centers[20] = (0.5876, 0.1557)\n centers[21] = (0.9093, 0.4304)\n centers[22] = (0.5509, 0.6373)\n centers[23] = (0.6287, 0.8991)\n centers[24] = (0.8732, 0.6288)\n centers[25] = (0.8186, 0.1011)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.228192568862337 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_145/results/packing_viz.png", + "execution_time_mean": 39.158950897865, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..74e229acb1971592ea093508dda556a6e2b9d866 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_145/rewrite.txt @@ -0,0 +1,241 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using a Hybrid Force-Directed Relaxation and Adaptive Simulated Annealing search""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i] = 0 + radii[j] = 0 + changes_made = True + + if not changes_made: + break + + return radii + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Use the same asymmetric starting point as successful previous models + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _apply_force_directed_relaxation(self, centers_to_relax, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies an aggressive force-directed relaxation algorithm to shake the initial grid. + """ + n_local = centers_to_relax.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers_to_relax) + + # Circle-circle repulsion + for i in range(n_local): + for j in range(i + 1, n_local): + vec = centers_to_relax[i] - centers_to_relax[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n_local): + x, y = centers_to_relax[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + centers_to_relax += step_size * forces + centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) + return centers_to_relax + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius and proximity to boundaries. + """ + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + # More sensitive to boundary proximity to encourage edge/corner optimization + boundary_proximity_weight = np.exp(-dist_to_nearest_boundary / 0.05) + + combined_weights = inverse_radii * (1 + boundary_proximity_weight) + selection_probs = combined_weights / np.sum(combined_weights) + + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength. Smaller circles get a bigger push. + """ + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + # Increase multiplier to 2.5 for more aggressive movement of small circles + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.5 + + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing. + """ + self._initialize_centers() + + # Pre-optimization with an aggressive Force-Directed Relaxation stage to break the grid + self.centers = self._apply_force_directed_relaxation( + self.centers.copy(), + iterations=800, + step_size=0.002, + repulsion_strength=0.015, + repulsion_threshold=0.22, + boundary_strength=0.08, + boundary_margin=0.04 + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + total_iterations = 18000 + initial_global_perturb_strength_base = 0.05 # Higher initial perturbation + final_global_perturb_strength = 0.0002 + + T_initial = 0.25 # Much higher initial temperature for extensive exploration + T_final = 1e-7 + + no_improvement_count = 0 + max_no_improvement_steps = 600 + current_initial_global_perturb_strength = initial_global_perturb_strength_base + + for iteration in range(total_iterations): + # Schedules for perturbation and temperature + global_perturb_strength = current_initial_global_perturb_strength * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + effective_perturb_strength = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # SA acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + delta = candidate_sum_radii - current_sum_radii + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and check for stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + # Stagnation escape: temporarily boost perturbation + if no_improvement_count > max_no_improvement_steps: + current_initial_global_perturb_strength *= 1.25 # Stronger boost + no_improvement_count = 0 # Reset counter + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + """ + packer = CirclePacker(n=26) + return packer.pack() +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..67b6fcb4c7187202beb79dd1bfeb7f570bd9db8c Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..25f55e0d3b54ca80a49faaca201fe086d82b3c39 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/edit.diff @@ -0,0 +1,394 @@ +--- a/original.py ++++ b/original.py +@@ -1,298 +1,348 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + + # compute_max_radii remains unchanged as it's a robust evaluation function. + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + + class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Use np.divide with where clause to handle potential division by zero for diff/dists + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = self.centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + +- cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation +- + # Stagnation detection and escape parameters + no_improvement_count = 0 + max_no_improvement_steps = 1000 # Iterations without improvement to trigger a boost + perturb_boost = 1.0 + boost_factor = 4.0 # A strong, but not excessively disruptive, kick + boost_decay = 0.95 # Gradual decay of the boost + + for iteration in range(total_iterations): +- # Logarithmic decay for temperature and perturbation strength ++ # Logarithmic decay for temperature and base perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Check for stagnation and apply a temporary perturbation boost + if no_improvement_count >= max_no_improvement_steps: + perturb_boost = boost_factor + no_improvement_count = 0 # Reset counter after triggering boost + ++ # Apply temporary perturbation boost, then decay it ++ current_base_perturb_strength_with_boost = base_perturb_strength * perturb_boost ++ if perturb_boost > 1.0: ++ perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay # Decay towards 1.0 ++ + candidate_centers = current_centers.copy() + +- # Target smaller circles for perturbation to help them grow and rearrange +- # Add small constant to avoid div by zero, and ensure it's calculated from current_radii +- inverse_radii = 1 / (current_radii + 1e-8) +- selection_probs = inverse_radii / np.sum(inverse_radii) +- +- # --- Clustered or Single Circle Perturbation --- +- if np.random.rand() < cluster_perturb_prob: +- # Clustered perturbation: select a primary circle, then its nearest neighbors +- primary_idx = np.random.choice(self.n, p=selection_probs) +- +- # Find the 2 closest neighbors (excluding self) +- distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) +- # Use argsort to get indices of circles sorted by distance +- # Skip the first element which is the primary_idx itself (distance 0) +- neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors +- +- # Collect all indices to perturb: primary + neighbors +- indices_to_perturb = [primary_idx] +- indices_to_perturb.extend(neighbor_indices) +- +- # Calculate adaptive perturbation strength based on the primary circle's inverse radius +- avg_inverse_radius = np.mean(inverse_radii) +- scale_factor = inverse_radii[primary_idx] / avg_inverse_radius +- # Clamp the scale factor to prevent excessively large or small perturbations. +- effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost +- +- # Generate a single displacement vector for the entire cluster +- displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +- +- # Apply the displacement to all circles in the cluster +- for idx in indices_to_perturb: +- candidate_centers[idx] += displacement +- candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) ++ # Calculate selection probabilities: prioritize smaller circles AND overlapping circles ++ inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero ++ inverse_radii_normalized = inverse_radii / np.sum(inverse_radii) ++ ++ overlap_scores = np.zeros(self.n) ++ for i in range(self.n): ++ for j in range(i + 1, self.n): ++ dist = np.linalg.norm(current_centers[i] - current_centers[j]) ++ current_rad_sum = current_radii[i] + current_radii[j] ++ if current_rad_sum > dist: # There's an overlap ++ overlap_amount = current_rad_sum - dist ++ overlap_scores[i] += overlap_amount ++ overlap_scores[j] += overlap_amount ++ ++ # Normalize overlap scores if there are any, otherwise set to zero ++ if np.sum(overlap_scores) > 1e-9: ++ normalized_overlap_scores = overlap_scores / np.sum(overlap_scores) + else: +- # Single circle perturbation ++ normalized_overlap_scores = np.zeros(self.n) ++ ++ # Combine inverse_radii and normalized_overlap_scores for selection ++ # Adjust weights: more weight on inverse_radii, but significant weight on overlap ++ combined_selection_criteria = (inverse_radii_normalized * 0.6 + normalized_overlap_scores * 0.4) ++ # Ensure selection_probs sums to 1. Handle case where all criteria are zero. ++ sum_criteria = np.sum(combined_selection_criteria) ++ if sum_criteria > 1e-9: ++ selection_probs = combined_selection_criteria / sum_criteria ++ else: # Fallback to uniform if no specific criteria to follow (e.g., all radii 0, no overlaps) ++ selection_probs = np.ones(self.n) / self.n ++ ++ # Decide between dual rotational and single translational perturbation ++ dual_rotational_perturb_prob = 0.20 # Probability of performing a dual rotational perturbation ++ ++ if np.random.rand() < dual_rotational_perturb_prob: ++ # Dual Rotational Perturbation: select two circles and rotate them around their midpoint ++ # Select a primary circle based on the combined selection probabilities ++ c1_idx = np.random.choice(self.n, p=selection_probs) ++ ++ # Find the closest neighbor (excluding self) ++ distances_to_c1 = np.linalg.norm(current_centers - current_centers[c1_idx], axis=1) ++ distances_to_c1[c1_idx] = np.inf # Exclude self ++ ++ # If no other circle exists or all are at inf, fallback to single perturbation ++ if np.min(distances_to_c1) == np.inf: ++ # Fallback to single translational perturbation for the primary circle ++ circle_idx = c1_idx ++ ++ # Calculate adaptive perturbation strength ++ avg_inverse_radius = np.mean(inverse_radii) ++ scale_factor = inverse_radii[circle_idx] / avg_inverse_radius ++ effective_perturb_strength = current_base_perturb_strength_with_boost * np.clip(scale_factor, 0.7, 2.5) ++ ++ # Apply a random displacement ++ displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) ++ else: ++ c2_idx = np.argmin(distances_to_c1) # The closest neighbor index ++ ++ # Calculate adaptive perturbation strength for the rotational angle ++ avg_inverse_radius = np.mean(inverse_radii) ++ scale_factor_c1 = inverse_radii[c1_idx] / avg_inverse_radius ++ effective_perturb_strength_for_angle = current_base_perturb_strength_with_boost * np.clip(scale_factor_c1, 0.7, 2.5) ++ ++ # Get centers and midpoint ++ center1 = candidate_centers[c1_idx] ++ center2 = candidate_centers[c2_idx] ++ midpoint = (center1 + center2) / 2 ++ ++ vec_c1_to_mid = center1 - midpoint # Vector from midpoint to center1 ++ ++ # Rotate by a small random angle. Angle magnitude scaled by effective_perturb_strength ++ # Max angle starts at 0.5 radians (approx 28 degrees) and decays with perturb_strength ++ max_angle_rad = 0.5 * (effective_perturb_strength_for_angle / initial_perturb_strength) ++ angle = np.random.uniform(-max_angle_rad, max_angle_rad) ++ ++ cos_angle = np.cos(angle) ++ sin_angle = np.sin(angle) ++ rotation_matrix = np.array([[cos_angle, -sin_angle], [sin_angle, cos_angle]]) ++ ++ vec_c1_rotated = np.dot(rotation_matrix, vec_c1_to_mid) ++ ++ candidate_centers[c1_idx] = np.clip(midpoint + vec_c1_rotated, 0.0, 1.0) ++ candidate_centers[c2_idx] = np.clip(midpoint - vec_c1_rotated, 0.0, 1.0) # c2 moves opposite to c1 relative to midpoint ++ else: ++ # Single Circle Translational Perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius +- effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost ++ effective_perturb_strength = current_base_perturb_strength_with_boost * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +- +- # Decay the perturbation boost so its effect is temporary +- if perturb_boost > 1.0: +- perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it and reset stagnation counter + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + else: + # Reject the new state + no_improvement_count += 1 + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_local_search( +- total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy ++ total_iterations=18000, # Further increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/main.py new file mode 100644 index 0000000000000000000000000000000000000000..b09bb9fcb38044d6ec941691c2a5f315d3812984 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/main.py @@ -0,0 +1,348 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Use np.divide with where clause to handle potential division by zero for diff/dists + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = self.centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Stagnation detection and escape parameters + no_improvement_count = 0 + max_no_improvement_steps = 1000 # Iterations without improvement to trigger a boost + perturb_boost = 1.0 + boost_factor = 4.0 # A strong, but not excessively disruptive, kick + boost_decay = 0.95 # Gradual decay of the boost + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and base perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Check for stagnation and apply a temporary perturbation boost + if no_improvement_count >= max_no_improvement_steps: + perturb_boost = boost_factor + no_improvement_count = 0 # Reset counter after triggering boost + + # Apply temporary perturbation boost, then decay it + current_base_perturb_strength_with_boost = base_perturb_strength * perturb_boost + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay # Decay towards 1.0 + + candidate_centers = current_centers.copy() + + # Calculate selection probabilities: prioritize smaller circles AND overlapping circles + inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero + inverse_radii_normalized = inverse_radii / np.sum(inverse_radii) + + overlap_scores = np.zeros(self.n) + for i in range(self.n): + for j in range(i + 1, self.n): + dist = np.linalg.norm(current_centers[i] - current_centers[j]) + current_rad_sum = current_radii[i] + current_radii[j] + if current_rad_sum > dist: # There's an overlap + overlap_amount = current_rad_sum - dist + overlap_scores[i] += overlap_amount + overlap_scores[j] += overlap_amount + + # Normalize overlap scores if there are any, otherwise set to zero + if np.sum(overlap_scores) > 1e-9: + normalized_overlap_scores = overlap_scores / np.sum(overlap_scores) + else: + normalized_overlap_scores = np.zeros(self.n) + + # Combine inverse_radii and normalized_overlap_scores for selection + # Adjust weights: more weight on inverse_radii, but significant weight on overlap + combined_selection_criteria = (inverse_radii_normalized * 0.6 + normalized_overlap_scores * 0.4) + # Ensure selection_probs sums to 1. Handle case where all criteria are zero. + sum_criteria = np.sum(combined_selection_criteria) + if sum_criteria > 1e-9: + selection_probs = combined_selection_criteria / sum_criteria + else: # Fallback to uniform if no specific criteria to follow (e.g., all radii 0, no overlaps) + selection_probs = np.ones(self.n) / self.n + + # Decide between dual rotational and single translational perturbation + dual_rotational_perturb_prob = 0.20 # Probability of performing a dual rotational perturbation + + if np.random.rand() < dual_rotational_perturb_prob: + # Dual Rotational Perturbation: select two circles and rotate them around their midpoint + # Select a primary circle based on the combined selection probabilities + c1_idx = np.random.choice(self.n, p=selection_probs) + + # Find the closest neighbor (excluding self) + distances_to_c1 = np.linalg.norm(current_centers - current_centers[c1_idx], axis=1) + distances_to_c1[c1_idx] = np.inf # Exclude self + + # If no other circle exists or all are at inf, fallback to single perturbation + if np.min(distances_to_c1) == np.inf: + # Fallback to single translational perturbation for the primary circle + circle_idx = c1_idx + + # Calculate adaptive perturbation strength + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = current_base_perturb_strength_with_boost * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + else: + c2_idx = np.argmin(distances_to_c1) # The closest neighbor index + + # Calculate adaptive perturbation strength for the rotational angle + avg_inverse_radius = np.mean(inverse_radii) + scale_factor_c1 = inverse_radii[c1_idx] / avg_inverse_radius + effective_perturb_strength_for_angle = current_base_perturb_strength_with_boost * np.clip(scale_factor_c1, 0.7, 2.5) + + # Get centers and midpoint + center1 = candidate_centers[c1_idx] + center2 = candidate_centers[c2_idx] + midpoint = (center1 + center2) / 2 + + vec_c1_to_mid = center1 - midpoint # Vector from midpoint to center1 + + # Rotate by a small random angle. Angle magnitude scaled by effective_perturb_strength + # Max angle starts at 0.5 radians (approx 28 degrees) and decays with perturb_strength + max_angle_rad = 0.5 * (effective_perturb_strength_for_angle / initial_perturb_strength) + angle = np.random.uniform(-max_angle_rad, max_angle_rad) + + cos_angle = np.cos(angle) + sin_angle = np.sin(angle) + rotation_matrix = np.array([[cos_angle, -sin_angle], [sin_angle, cos_angle]]) + + vec_c1_rotated = np.dot(rotation_matrix, vec_c1_to_mid) + + candidate_centers[c1_idx] = np.clip(midpoint + vec_c1_rotated, 0.0, 1.0) + candidate_centers[c2_idx] = np.clip(midpoint - vec_c1_rotated, 0.0, 1.0) # c2 moves opposite to c1 relative to midpoint + else: + # Single Circle Translational Perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = current_base_perturb_strength_with_boost * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it and reset stagnation counter + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + else: + # Reject the new state + no_improvement_count += 1 + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_local_search( + total_iterations=18000, # Further increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/original.py new file mode 100644 index 0000000000000000000000000000000000000000..32faf10c71aef93ec79e2f49a4765eb2f067e5e9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/original.py @@ -0,0 +1,298 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Use np.divide with where clause to handle potential division by zero for diff/dists + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = self.centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + # Stagnation detection and escape parameters + no_improvement_count = 0 + max_no_improvement_steps = 1000 # Iterations without improvement to trigger a boost + perturb_boost = 1.0 + boost_factor = 4.0 # A strong, but not excessively disruptive, kick + boost_decay = 0.95 # Gradual decay of the boost + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Check for stagnation and apply a temporary perturbation boost + if no_improvement_count >= max_no_improvement_steps: + perturb_boost = boost_factor + no_improvement_count = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it and reset stagnation counter + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + else: + # Reject the new state + no_improvement_count += 1 + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_local_search( + total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..afa9b7c84392cf74f045d70dd1badd5d8acf0f62 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_147/main.py:101: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..186ed6b20a3f41da8af4413495d65a4a9cedccaa --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_147/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_147/results +Run 1/1 completed in 59.41 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.2147861617321767 + public: {'centers_str': ' centers[0] = (0.1070, 0.1070)\n centers[1] = (0.3371, 0.1236)\n centers[2] = (0.5270, 0.0730)\n centers[3] = (0.7120, 0.0883)\n centers[4] = (0.8999, 0.0999)\n centers[5] = (0.0913, 0.3047)\n centers[6] = (0.4453, 0.6376)\n centers[7] = (0.4837, 0.3159)\n centers[8] = (0.6942, 0.2544)\n centers[9] = (0.9020, 0.2979)\n centers[10] = (0.0991, 0.5061)\n centers[11] = (0.2980, 0.4311)\n centers[12] = (0.4288, 0.5505)\n centers[13] = (0.7952, 0.5928)\n centers[14] = (0.9300, 0.4635)\n centers[15] = (0.0968, 0.7021)\n centers[16] = (0.3126, 0.6853)\n centers[17] = (0.5123, 0.6857)\n centers[18] = (0.6984, 0.7355)\n centers[19] = (0.9047, 0.7021)\n centers[20] = (0.1005, 0.8994)\n centers[21] = (0.2989, 0.9022)\n centers[22] = (0.5193, 0.8826)\n centers[23] = (0.7222, 0.9234)\n centers[24] = (0.8985, 0.8986)\n centers[25] = (0.6206, 0.4920)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.2147861617321767} + visualization_path: + execution_time_mean: 59.41484477976337 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..3df78cff5db3d4a8b9eea84ee5c8f3df9d39ab5b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.2147861617321767, + "public": { + "centers_str": " centers[0] = (0.1070, 0.1070)\n centers[1] = (0.3371, 0.1236)\n centers[2] = (0.5270, 0.0730)\n centers[3] = (0.7120, 0.0883)\n centers[4] = (0.8999, 0.0999)\n centers[5] = (0.0913, 0.3047)\n centers[6] = (0.4453, 0.6376)\n centers[7] = (0.4837, 0.3159)\n centers[8] = (0.6942, 0.2544)\n centers[9] = (0.9020, 0.2979)\n centers[10] = (0.0991, 0.5061)\n centers[11] = (0.2980, 0.4311)\n centers[12] = (0.4288, 0.5505)\n centers[13] = (0.7952, 0.5928)\n centers[14] = (0.9300, 0.4635)\n centers[15] = (0.0968, 0.7021)\n centers[16] = (0.3126, 0.6853)\n centers[17] = (0.5123, 0.6857)\n centers[18] = (0.6984, 0.7355)\n centers[19] = (0.9047, 0.7021)\n centers[20] = (0.1005, 0.8994)\n centers[21] = (0.2989, 0.9022)\n centers[22] = (0.5193, 0.8826)\n centers[23] = (0.7222, 0.9234)\n centers[24] = (0.8985, 0.8986)\n centers[25] = (0.6206, 0.4920)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.2147861617321767 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_147/results/packing_viz.png", + "execution_time_mean": 59.41484477976337, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7e91ec67cb7ffd1805c371f3f77f8758334601a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_147/search_replace.txt @@ -0,0 +1,290 @@ + +The current visualization shows some persistent inefficiencies, particularly the presence of very small circles in underutilized areas and a not-quite-optimal distribution, indicating that the search might be getting stuck in local optima. The previous `clustered_perturbation` involved multiple circles moving in the same direction, which might not be ideal for breaking local tight-packing symmetries. + +This edit proposes a significant enhancement to the `_simulated_annealing_local_search` method by introducing a `dual_rotational_perturbation` operator and refining the circle selection probabilities. + +**Key Changes:** +1. **Refined Selection Probability**: The `selection_probs` now consider both the `inverse_radii` (to prioritize smaller circles, helping them grow or escape) and a newly calculated `overlap_scores` (to prioritize circles currently involved in overlaps, thus directly addressing inefficiencies). This directs the perturbation effort more intelligently. +2. **Dual Rotational Perturbation**: Replaces the previous "clustered perturbation" (which just moved multiple circles in the same direction) with a `dual_rotational_perturbation`. + * With a probability of 20%, two circles are selected: a primary circle (based on the refined `selection_probs`) and its closest neighbor. + * These two circles are then rotated around their midpoint by a small, randomly chosen angle. This type of perturbation is highly effective for breaking local symmetries in tightly packed regions, allowing circles to "roll" past each other and find better interlocking configurations. The magnitude of the rotation angle is scaled by the current perturbation strength, ensuring it adapts throughout the annealing process. + * A fallback to a single translational perturbation is included if a suitable neighbor for dual perturbation isn't found. +3. **Consistent Perturbation Strength Calculation**: The calculation of `effective_perturb_strength` now consistently incorporates the `perturb_boost` (for stagnation escape) before scaling by `inverse_radii`, ensuring that the boost correctly influences both single and dual perturbations. +4. **Increased Iterations**: The total iterations for the SA phase have been slightly increased from 15000 to 18000 to give the new perturbation strategies more time to explore the solution space effectively. + +This hybrid approach, combining targeted selection, a geometrically effective rotational move, and robust annealing parameters, aims to explore the solution space more thoroughly and escape local minima that traditional translational perturbations might miss, leading to a higher sum of radii. + + +<<<<<<< SEARCH + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + # Stagnation detection and escape parameters + no_improvement_count = 0 + max_no_improvement_steps = 1000 # Iterations without improvement to trigger a boost + perturb_boost = 1.0 + boost_factor = 4.0 # A strong, but not excessively disruptive, kick + boost_decay = 0.95 # Gradual decay of the boost + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Check for stagnation and apply a temporary perturbation boost + if no_improvement_count >= max_no_improvement_steps: + perturb_boost = boost_factor + no_improvement_count = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it and reset stagnation counter + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + else: + # Reject the new state + no_improvement_count += 1 +======= + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Stagnation detection and escape parameters + no_improvement_count = 0 + max_no_improvement_steps = 1000 # Iterations without improvement to trigger a boost + perturb_boost = 1.0 + boost_factor = 4.0 # A strong, but not excessively disruptive, kick + boost_decay = 0.95 # Gradual decay of the boost + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and base perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Check for stagnation and apply a temporary perturbation boost + if no_improvement_count >= max_no_improvement_steps: + perturb_boost = boost_factor + no_improvement_count = 0 # Reset counter after triggering boost + + # Apply temporary perturbation boost, then decay it + current_base_perturb_strength_with_boost = base_perturb_strength * perturb_boost + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay # Decay towards 1.0 + + candidate_centers = current_centers.copy() + + # Calculate selection probabilities: prioritize smaller circles AND overlapping circles + inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero + inverse_radii_normalized = inverse_radii / np.sum(inverse_radii) + + overlap_scores = np.zeros(self.n) + for i in range(self.n): + for j in range(i + 1, self.n): + dist = np.linalg.norm(current_centers[i] - current_centers[j]) + current_rad_sum = current_radii[i] + current_radii[j] + if current_rad_sum > dist: # There's an overlap + overlap_amount = current_rad_sum - dist + overlap_scores[i] += overlap_amount + overlap_scores[j] += overlap_amount + + # Normalize overlap scores if there are any, otherwise set to zero + if np.sum(overlap_scores) > 1e-9: + normalized_overlap_scores = overlap_scores / np.sum(overlap_scores) + else: + normalized_overlap_scores = np.zeros(self.n) + + # Combine inverse_radii and normalized_overlap_scores for selection + # Adjust weights: more weight on inverse_radii, but significant weight on overlap + combined_selection_criteria = (inverse_radii_normalized * 0.6 + normalized_overlap_scores * 0.4) + # Ensure selection_probs sums to 1. Handle case where all criteria are zero. + sum_criteria = np.sum(combined_selection_criteria) + if sum_criteria > 1e-9: + selection_probs = combined_selection_criteria / sum_criteria + else: # Fallback to uniform if no specific criteria to follow (e.g., all radii 0, no overlaps) + selection_probs = np.ones(self.n) / self.n + + # Decide between dual rotational and single translational perturbation + dual_rotational_perturb_prob = 0.20 # Probability of performing a dual rotational perturbation + + if np.random.rand() < dual_rotational_perturb_prob: + # Dual Rotational Perturbation: select two circles and rotate them around their midpoint + # Select a primary circle based on the combined selection probabilities + c1_idx = np.random.choice(self.n, p=selection_probs) + + # Find the closest neighbor (excluding self) + distances_to_c1 = np.linalg.norm(current_centers - current_centers[c1_idx], axis=1) + distances_to_c1[c1_idx] = np.inf # Exclude self + + # If no other circle exists or all are at inf, fallback to single perturbation + if np.min(distances_to_c1) == np.inf: + # Fallback to single translational perturbation for the primary circle + circle_idx = c1_idx + + # Calculate adaptive perturbation strength + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = current_base_perturb_strength_with_boost * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + else: + c2_idx = np.argmin(distances_to_c1) # The closest neighbor index + + # Calculate adaptive perturbation strength for the rotational angle + avg_inverse_radius = np.mean(inverse_radii) + scale_factor_c1 = inverse_radii[c1_idx] / avg_inverse_radius + effective_perturb_strength_for_angle = current_base_perturb_strength_with_boost * np.clip(scale_factor_c1, 0.7, 2.5) + + # Get centers and midpoint + center1 = candidate_centers[c1_idx] + center2 = candidate_centers[c2_idx] + midpoint = (center1 + center2) / 2 + + vec_c1_to_mid = center1 - midpoint # Vector from midpoint to center1 + + # Rotate by a small random angle. Angle magnitude scaled by effective_perturb_strength + # Max angle starts at 0.5 radians (approx 28 degrees) and decays with perturb_strength + max_angle_rad = 0.5 * (effective_perturb_strength_for_angle / initial_perturb_strength) + angle = np.random.uniform(-max_angle_rad, max_angle_rad) + + cos_angle = np.cos(angle) + sin_angle = np.sin(angle) + rotation_matrix = np.array([[cos_angle, -sin_angle], [sin_angle, cos_angle]]) + + vec_c1_rotated = np.dot(rotation_matrix, vec_c1_to_mid) + + candidate_centers[c1_idx] = np.clip(midpoint + vec_c1_rotated, 0.0, 1.0) + candidate_centers[c2_idx] = np.clip(midpoint - vec_c1_rotated, 0.0, 1.0) # c2 moves opposite to c1 relative to midpoint + else: + # Single Circle Translational Perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = current_base_perturb_strength_with_boost * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it and reset stagnation counter + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + else: + # Reject the new state + no_improvement_count += 1 +>>>>>>> REPLACE + + +<<<<<<< SEARCH + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_local_search( + total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) +======= + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_local_search( + total_iterations=18000, # Further increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3cc6244bcec68cee78543040c8c5e3b7f70de066 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..33c42aafe58af6a543d75fa5cfc71cdb066e4a89 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/edit.diff @@ -0,0 +1,354 @@ +--- a/original.py ++++ b/original.py +@@ -1,251 +1,177 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + +-# compute_max_radii remains unchanged as it's a robust evaluation function. ++# compute_max_radii is kept as a high-precision evaluation function, ++# particularly for the final result. + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. +- +- Args: +- centers: np.array of shape (n, 2) with (x, y) coordinates +- +- Returns: +- np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] +- +- # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +-class CirclePacker: ++class GravitationalGrower: + """ +- A class to encapsulate the state and logic for packing circles using +- a hybrid approach: initial aggressive perturbation, a quick force-directed +- relaxation, and then a primary optimization via simulated annealing. +- This version includes cluster perturbations and stagnation escape. ++ Packs circles using a dynamic growth and physics-based relaxation method. ++ It avoids local search metaheuristics in favor of a constructive, ++ globally coordinated process. + """ ++ def __init__(self, n): ++ self.n = n ++ # Start with random centers and tiny, uniform radii ++ self.centers = np.random.rand(n, 2) * 0.8 + 0.1 # Start away from edges ++ self.radii = np.full(n, 0.01) + +- def __init__(self, n=26): +- """Initializes the packer with the number of circles.""" +- self.n = n +- self.centers = np.zeros((n, 2)) +- +- def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): ++ def _apply_forces(self, iters, step_size, repulsion_strength, attraction_strength, boundary_strength): + """ +- Generates an initial configuration by creating a base 5x5 grid, +- aggressively deforming it to create a void, and placing the 26th circle. ++ Applies forces to centers. Can be repulsive, attractive, or both. + """ +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T +- +- displacements = base_centers_25 - void_center +- distances = np.linalg.norm(displacements, axis=1) +- mask = distances > 1e-9 +- +- push_magnitudes = np.zeros(25) +- push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) +- +- if np.any(mask): +- displacements[mask] /= distances[mask, np.newaxis] +- +- initial_centers = np.zeros((self.n, 2)) +- initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- initial_centers[25] = void_center +- self.centers = np.clip(initial_centers, 0.0, 1.0) +- +- def _force_directed_relaxation(self, iters, step_size, repulsion_strength, +- boundary_strength, repulsion_threshold, boundary_margin): +- """ +- Applies a force-directed relaxation step using vectorized calculations. +- """ ++ boundary_margin = 0.01 + for _ in range(iters): ++ # Vectorized distance calculation + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) ++ ++ # Initialize force vectors ++ forces = np.zeros_like(self.centers) + +- mask = (dists > 1e-9) & (dists < repulsion_threshold) +- +- force_scalar = np.zeros_like(dists) +- force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] ++ # 1. Repulsive forces for overlapping circles ++ if repulsion_strength > 0: ++ radii_sum = self.radii[:, np.newaxis] + self.radii[np.newaxis, :] ++ overlap_mask = (dists < radii_sum) & (dists > 1e-9) ++ ++ # Calculate overlap amount ++ overlap_amount = radii_sum[overlap_mask] - dists[overlap_mask] ++ ++ # Normalize difference vectors safely ++ force_dir = np.divide(diff[overlap_mask], dists[overlap_mask, np.newaxis]) + +- force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +- forces = np.sum(force_vectors, axis=1) ++ # Apply force proportional to overlap ++ force_vectors = (repulsion_strength * overlap_amount)[:, np.newaxis] * force_dir ++ ++ # Add forces to an accumulator array for correctness ++ np.add.at(forces, np.where(overlap_mask)[0], force_vectors) + ++ # 2. Attractive forces for compaction ++ if attraction_strength > 0: ++ # Weak, global attraction. Avoid singularity at dist=0. ++ force_magnitudes = attraction_strength / (dists**2 + 0.01) ++ # Normalize diff vector ++ force_dir = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ attractive_force_vectors = force_magnitudes[:, :, np.newaxis] * force_dir ++ total_attraction = np.sum(attractive_force_vectors, axis=1) ++ forces -= total_attraction ++ ++ # 3. Boundary repulsion forces + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) +- ++ ++ # Update centers + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + +- def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, +- initial_perturb_strength, final_perturb_strength): ++ def pack(self): + """ +- Performs a simulated annealing optimization with cluster perturbations and +- stagnation detection to escape local optima. ++ Executes the main grow-and-resolve loop. + """ + best_centers = self.centers.copy() +- best_radii = compute_max_radii(best_centers) +- best_sum_radii = np.sum(best_radii) ++ best_sum_radii = 0.0 + +- current_centers = self.centers.copy() +- current_radii = best_radii.copy() +- current_sum_radii = best_sum_radii ++ total_iterations = 3500 ++ compaction_frequency = 50 + +- # Parameters for advanced SA features +- cluster_perturb_prob = 0.20 # Increased probability for coordinated moves +- no_improvement_count = 0 +- max_no_improvement_steps = 1200 # Trigger boost after this many steps without finding a new best +- perturb_boost = 1.0 +- boost_factor = 4.0 # A strong kick +- boost_decay = 0.97 # Slower decay for a longer-lasting effect ++ for i in range(total_iterations): ++ progress = i / total_iterations ++ ++ # 1. Growth Phase: Uniformly grow all circles ++ growth_rate = 0.0004 * (1 - progress)**2 + 0.00001 ++ self.radii += growth_rate + +- for iteration in range(total_iterations): +- progress = iteration / total_iterations +- temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) +- base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) ++ # Cap radii by boundary distance ++ dist_to_boundary = np.min([self.centers[:, 0], 1 - self.centers[:, 0], self.centers[:, 1], 1 - self.centers[:, 1]], axis=0) ++ self.radii = np.minimum(self.radii, dist_to_boundary) + +- # Stagnation detection and boost logic +- if no_improvement_count >= max_no_improvement_steps: +- perturb_boost = boost_factor +- no_improvement_count = 0 ++ # 2. Overlap Resolution Phase: Strong, short-range repulsion ++ self._apply_forces( ++ iters=5, ++ step_size=0.01, ++ repulsion_strength=0.1, ++ attraction_strength=0, ++ boundary_strength=0.5 ++ ) + +- candidate_centers = current_centers.copy() +- +- inverse_radii = 1 / (current_radii + 1e-8) +- selection_probs = inverse_radii / np.sum(inverse_radii) ++ # 3. Periodic Gravitational Compaction ++ if i > 500 and i % compaction_frequency == 0: ++ self._apply_forces( ++ iters=10, ++ step_size=0.005, ++ repulsion_strength=0.02, # Weak repulsion to prevent collapse ++ attraction_strength=0.00002, # Weak but global attraction ++ boundary_strength=1.0 # Very strong boundaries ++ ) + +- # Cluster Perturbation Logic +- if np.random.rand() < cluster_perturb_prob: +- primary_idx = np.random.choice(self.n, p=selection_probs) ++ # 4. Track Best Solution ++ current_sum_radii = np.sum(self.radii) ++ if current_sum_radii > best_sum_radii: ++ # Check for overlaps before declaring a new best. ++ is_valid = True ++ temp_radii = self.radii.copy() ++ temp_centers = self.centers.copy() ++ for k in range(self.n): ++ for j in range(k + 1, self.n): ++ if np.linalg.norm(temp_centers[k] - temp_centers[j]) < temp_radii[k] + temp_radii[j] - 1e-9: ++ is_valid = False ++ break ++ if not is_valid: ++ break + +- distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) +- neighbor_indices = np.argsort(distances_to_primary)[1:3] +- +- indices_to_perturb = [primary_idx] + list(neighbor_indices) +- +- effective_perturb_strength = base_perturb_strength * perturb_boost +- displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +- +- for idx in indices_to_perturb: +- candidate_centers[idx] += displacement +- candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) +- else: +- # Single-circle perturbation +- circle_idx = np.random.choice(self.n, p=selection_probs) +- effective_perturb_strength = base_perturb_strength * perturb_boost +- displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +- candidate_centers[circle_idx] += displacement +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +- +- # Decay the boost +- if perturb_boost > 1.0: +- perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay ++ if is_valid: ++ best_sum_radii = current_sum_radii ++ best_centers = self.centers.copy() + +- candidate_radii = compute_max_radii(candidate_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- delta_E = candidate_sum_radii - current_sum_radii +- if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): +- current_sum_radii = candidate_sum_radii +- current_centers = candidate_centers +- current_radii = candidate_radii +- +- if current_sum_radii > best_sum_radii: +- best_sum_radii = current_sum_radii +- best_centers = current_centers.copy() +- best_radii = current_radii.copy() +- no_improvement_count = 0 +- else: +- no_improvement_count += 1 +- else: +- no_improvement_count += 1 +- +- self.centers = best_centers +- return best_radii +- +- def pack(self): +- """ +- Orchestrates the packing process using a multi-phase, adaptive algorithm. +- """ +- # 1. Randomized Initial Void +- random_void_center = np.random.uniform(0.3, 0.7, 2) +- self._initial_placement_with_void_and_perturbation( +- void_center=random_void_center, +- amplitude=0.09, # Slightly stronger initial push +- sigma=0.18 # Broader push area +- ) +- +- # 2. Aggressive FDR to resolve initial chaos +- self._force_directed_relaxation( +- iters=600, # Longer initial relaxation for more varied starts +- step_size=0.002, +- repulsion_strength=0.02, +- boundary_strength=0.08, +- repulsion_threshold=0.19, +- boundary_margin=0.04 +- ) +- +- # 3. Enhanced Simulated Annealing for global optimization +- self._simulated_annealing_local_search( +- total_iterations=18000, # More iterations for the enhanced search +- initial_temp=0.0008, # Higher initial temp for more exploration +- final_temp=1e-9, # Low final temp for refinement +- initial_perturb_strength=0.035, # Higher initial move size +- final_perturb_strength=0.0001 +- ) +- +- # 4. Final gentle FDR for polishing +- self._force_directed_relaxation( +- iters=300, +- step_size=0.0001, +- repulsion_strength=0.001, +- boundary_strength=0.005, +- repulsion_threshold=0.18, +- boundary_margin=0.02 +- ) +- +- final_radii = compute_max_radii(self.centers) +- return self.centers, final_radii ++ # Final Polish: Use the precise compute_max_radii on the best found centers ++ final_radii = compute_max_radii(best_centers) ++ return best_centers, final_radii + + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles using the CirclePacker class. ++ Constructs a high-density arrangement of 26 circles using the ++ GravitationalGrower class. + """ +- packer = CirclePacker(n=26) ++ packer = GravitationalGrower(n=26) + centers, radii = packer.pack() + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/main.py new file mode 100644 index 0000000000000000000000000000000000000000..51b75f7b8009a07f5094b0c393f1d452c5e4551c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/main.py @@ -0,0 +1,177 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii is kept as a high-precision evaluation function, +# particularly for the final result. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class GravitationalGrower: + """ + Packs circles using a dynamic growth and physics-based relaxation method. + It avoids local search metaheuristics in favor of a constructive, + globally coordinated process. + """ + def __init__(self, n): + self.n = n + # Start with random centers and tiny, uniform radii + self.centers = np.random.rand(n, 2) * 0.8 + 0.1 # Start away from edges + self.radii = np.full(n, 0.01) + + def _apply_forces(self, iters, step_size, repulsion_strength, attraction_strength, boundary_strength): + """ + Applies forces to centers. Can be repulsive, attractive, or both. + """ + boundary_margin = 0.01 + for _ in range(iters): + # Vectorized distance calculation + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Initialize force vectors + forces = np.zeros_like(self.centers) + + # 1. Repulsive forces for overlapping circles + if repulsion_strength > 0: + radii_sum = self.radii[:, np.newaxis] + self.radii[np.newaxis, :] + overlap_mask = (dists < radii_sum) & (dists > 1e-9) + + # Calculate overlap amount + overlap_amount = radii_sum[overlap_mask] - dists[overlap_mask] + + # Normalize difference vectors safely + force_dir = np.divide(diff[overlap_mask], dists[overlap_mask, np.newaxis]) + + # Apply force proportional to overlap + force_vectors = (repulsion_strength * overlap_amount)[:, np.newaxis] * force_dir + + # Add forces to an accumulator array for correctness + np.add.at(forces, np.where(overlap_mask)[0], force_vectors) + + # 2. Attractive forces for compaction + if attraction_strength > 0: + # Weak, global attraction. Avoid singularity at dist=0. + force_magnitudes = attraction_strength / (dists**2 + 0.01) + # Normalize diff vector + force_dir = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + attractive_force_vectors = force_magnitudes[:, :, np.newaxis] * force_dir + total_attraction = np.sum(attractive_force_vectors, axis=1) + forces -= total_attraction + + # 3. Boundary repulsion forces + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + # Update centers + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def pack(self): + """ + Executes the main grow-and-resolve loop. + """ + best_centers = self.centers.copy() + best_sum_radii = 0.0 + + total_iterations = 3500 + compaction_frequency = 50 + + for i in range(total_iterations): + progress = i / total_iterations + + # 1. Growth Phase: Uniformly grow all circles + growth_rate = 0.0004 * (1 - progress)**2 + 0.00001 + self.radii += growth_rate + + # Cap radii by boundary distance + dist_to_boundary = np.min([self.centers[:, 0], 1 - self.centers[:, 0], self.centers[:, 1], 1 - self.centers[:, 1]], axis=0) + self.radii = np.minimum(self.radii, dist_to_boundary) + + # 2. Overlap Resolution Phase: Strong, short-range repulsion + self._apply_forces( + iters=5, + step_size=0.01, + repulsion_strength=0.1, + attraction_strength=0, + boundary_strength=0.5 + ) + + # 3. Periodic Gravitational Compaction + if i > 500 and i % compaction_frequency == 0: + self._apply_forces( + iters=10, + step_size=0.005, + repulsion_strength=0.02, # Weak repulsion to prevent collapse + attraction_strength=0.00002, # Weak but global attraction + boundary_strength=1.0 # Very strong boundaries + ) + + # 4. Track Best Solution + current_sum_radii = np.sum(self.radii) + if current_sum_radii > best_sum_radii: + # Check for overlaps before declaring a new best. + is_valid = True + temp_radii = self.radii.copy() + temp_centers = self.centers.copy() + for k in range(self.n): + for j in range(k + 1, self.n): + if np.linalg.norm(temp_centers[k] - temp_centers[j]) < temp_radii[k] + temp_radii[j] - 1e-9: + is_valid = False + break + if not is_valid: + break + + if is_valid: + best_sum_radii = current_sum_radii + best_centers = self.centers.copy() + + # Final Polish: Use the precise compute_max_radii on the best found centers + final_radii = compute_max_radii(best_centers) + return best_centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the + GravitationalGrower class. + """ + packer = GravitationalGrower(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/original.py new file mode 100644 index 0000000000000000000000000000000000000000..5041f660822084877ef48be688951bc620ce7ccf --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/original.py @@ -0,0 +1,251 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + This version includes cluster perturbations and stagnation escape. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + """ + for _ in range(iters): + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization with cluster perturbations and + stagnation detection to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = self.centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Parameters for advanced SA features + cluster_perturb_prob = 0.20 # Increased probability for coordinated moves + no_improvement_count = 0 + max_no_improvement_steps = 1200 # Trigger boost after this many steps without finding a new best + perturb_boost = 1.0 + boost_factor = 4.0 # A strong kick + boost_decay = 0.97 # Slower decay for a longer-lasting effect + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Stagnation detection and boost logic + if no_improvement_count >= max_no_improvement_steps: + perturb_boost = boost_factor + no_improvement_count = 0 + + candidate_centers = current_centers.copy() + + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # Cluster Perturbation Logic + if np.random.rand() < cluster_perturb_prob: + primary_idx = np.random.choice(self.n, p=selection_probs) + + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + neighbor_indices = np.argsort(distances_to_primary)[1:3] + + indices_to_perturb = [primary_idx] + list(neighbor_indices) + + effective_perturb_strength = base_perturb_strength * perturb_boost + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single-circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + effective_perturb_strength = base_perturb_strength * perturb_boost + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the boost + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + else: + no_improvement_count += 1 + + self.centers = best_centers + return best_radii + + def pack(self): + """ + Orchestrates the packing process using a multi-phase, adaptive algorithm. + """ + # 1. Randomized Initial Void + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, + amplitude=0.09, # Slightly stronger initial push + sigma=0.18 # Broader push area + ) + + # 2. Aggressive FDR to resolve initial chaos + self._force_directed_relaxation( + iters=600, # Longer initial relaxation for more varied starts + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Enhanced Simulated Annealing for global optimization + self._simulated_annealing_local_search( + total_iterations=18000, # More iterations for the enhanced search + initial_temp=0.0008, # Higher initial temp for more exploration + final_temp=1e-9, # Low final temp for refinement + initial_perturb_strength=0.035, # Higher initial move size + final_perturb_strength=0.0001 + ) + + # 4. Final gentle FDR for polishing + self._force_directed_relaxation( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + final_radii = compute_max_radii(self.centers) + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..5b0644b07fa28899126c0cb3aae9a47ce0078ba0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_148/main.py:81: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_dir = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..e148c62669115b2ccc88cec732e5b747d9d524c9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_148/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_148/results +Run 1/1 completed in 2.32 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 0.9594523831810925 + public: {'centers_str': ' centers[0] = (0.6890, 0.5277)\n centers[1] = (0.7882, 0.5220)\n centers[2] = (0.7256, 0.7440)\n centers[3] = (0.5616, 0.8333)\n centers[4] = (0.7769, 0.3669)\n centers[5] = (0.6057, 0.5476)\n centers[6] = (0.5267, 0.8023)\n centers[7] = (0.7428, 0.8751)\n centers[8] = (0.6996, 0.4356)\n centers[9] = (0.7129, 0.4587)\n centers[10] = (0.7110, 0.1396)\n centers[11] = (0.1817, 0.6232)\n centers[12] = (0.3234, 0.7130)\n centers[13] = (0.7588, 0.6384)\n centers[14] = (0.8036, 0.1679)\n centers[15] = (0.1262, 0.8164)\n centers[16] = (0.7561, 0.5238)\n centers[17] = (0.2943, 0.1920)\n centers[18] = (0.5001, 0.8986)\n centers[19] = (0.6990, 0.6084)\n centers[20] = (0.6869, 0.6844)\n centers[21] = (0.1022, 0.8444)\n centers[22] = (0.2383, 0.5161)\n centers[23] = (0.4926, 0.1462)\n centers[24] = (0.2726, 0.2420)\n centers[25] = (0.6061, 0.5016)', 'num_circles': 26} + private: {'reported_sum_of_radii': 0.9594523831810925} + visualization_path: + execution_time_mean: 2.324986177030951 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..199572dc9c9e0637c878cc3750f78d335f4866bd --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 0.9594523831810925, + "public": { + "centers_str": " centers[0] = (0.6890, 0.5277)\n centers[1] = (0.7882, 0.5220)\n centers[2] = (0.7256, 0.7440)\n centers[3] = (0.5616, 0.8333)\n centers[4] = (0.7769, 0.3669)\n centers[5] = (0.6057, 0.5476)\n centers[6] = (0.5267, 0.8023)\n centers[7] = (0.7428, 0.8751)\n centers[8] = (0.6996, 0.4356)\n centers[9] = (0.7129, 0.4587)\n centers[10] = (0.7110, 0.1396)\n centers[11] = (0.1817, 0.6232)\n centers[12] = (0.3234, 0.7130)\n centers[13] = (0.7588, 0.6384)\n centers[14] = (0.8036, 0.1679)\n centers[15] = (0.1262, 0.8164)\n centers[16] = (0.7561, 0.5238)\n centers[17] = (0.2943, 0.1920)\n centers[18] = (0.5001, 0.8986)\n centers[19] = (0.6990, 0.6084)\n centers[20] = (0.6869, 0.6844)\n centers[21] = (0.1022, 0.8444)\n centers[22] = (0.2383, 0.5161)\n centers[23] = (0.4926, 0.1462)\n centers[24] = (0.2726, 0.2420)\n centers[25] = (0.6061, 0.5016)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 0.9594523831810925 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_148/results/packing_viz.png", + "execution_time_mean": 2.324986177030951, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..d236a0e156789ffd8f426b83fb4e5733fbc6c1f6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_148/rewrite.txt @@ -0,0 +1,168 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii is kept as a high-precision evaluation function, +# particularly for the final result. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class GravitationalGrower: + """ + Packs circles using a dynamic growth and physics-based relaxation method. + It avoids local search metaheuristics in favor of a constructive, + globally coordinated process. + """ + def __init__(self, n): + self.n = n + # Start with random centers and tiny, uniform radii + self.centers = np.random.rand(n, 2) * 0.8 + 0.1 # Start away from edges + self.radii = np.full(n, 0.01) + + def _apply_forces(self, iters, step_size, repulsion_strength, attraction_strength, boundary_strength): + """ + Applies forces to centers. Can be repulsive, attractive, or both. + """ + boundary_margin = 0.01 + for _ in range(iters): + # Vectorized distance calculation + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Initialize force vectors + forces = np.zeros_like(self.centers) + + # 1. Repulsive forces for overlapping circles + if repulsion_strength > 0: + radii_sum = self.radii[:, np.newaxis] + self.radii[np.newaxis, :] + overlap_mask = (dists < radii_sum) & (dists > 1e-9) + + # Calculate overlap amount + overlap_amount = radii_sum[overlap_mask] - dists[overlap_mask] + + # Normalize difference vectors safely + force_dir = np.divide(diff[overlap_mask], dists[overlap_mask, np.newaxis]) + + # Apply force proportional to overlap + force_vectors = (repulsion_strength * overlap_amount)[:, np.newaxis] * force_dir + + # Add forces to an accumulator array for correctness + np.add.at(forces, np.where(overlap_mask)[0], force_vectors) + + # 2. Attractive forces for compaction + if attraction_strength > 0: + # Weak, global attraction. Avoid singularity at dist=0. + force_magnitudes = attraction_strength / (dists**2 + 0.01) + # Normalize diff vector + force_dir = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + attractive_force_vectors = force_magnitudes[:, :, np.newaxis] * force_dir + total_attraction = np.sum(attractive_force_vectors, axis=1) + forces -= total_attraction + + # 3. Boundary repulsion forces + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + # Update centers + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def pack(self): + """ + Executes the main grow-and-resolve loop. + """ + best_centers = self.centers.copy() + best_sum_radii = 0.0 + + total_iterations = 3500 + compaction_frequency = 50 + + for i in range(total_iterations): + progress = i / total_iterations + + # 1. Growth Phase: Uniformly grow all circles + growth_rate = 0.0004 * (1 - progress)**2 + 0.00001 + self.radii += growth_rate + + # Cap radii by boundary distance + dist_to_boundary = np.min([self.centers[:, 0], 1 - self.centers[:, 0], self.centers[:, 1], 1 - self.centers[:, 1]], axis=0) + self.radii = np.minimum(self.radii, dist_to_boundary) + + # 2. Overlap Resolution Phase: Strong, short-range repulsion + self._apply_forces( + iters=5, + step_size=0.01, + repulsion_strength=0.1, + attraction_strength=0, + boundary_strength=0.5 + ) + + # 3. Periodic Gravitational Compaction + if i > 500 and i % compaction_frequency == 0: + self._apply_forces( + iters=10, + step_size=0.005, + repulsion_strength=0.02, # Weak repulsion to prevent collapse + attraction_strength=0.00002, # Weak but global attraction + boundary_strength=1.0 # Very strong boundaries + ) + + # 4. Track Best Solution + current_sum_radii = np.sum(self.radii) + if current_sum_radii > best_sum_radii: + # Check for overlaps before declaring a new best. + is_valid = True + temp_radii = self.radii.copy() + temp_centers = self.centers.copy() + for k in range(self.n): + for j in range(k + 1, self.n): + if np.linalg.norm(temp_centers[k] - temp_centers[j]) < temp_radii[k] + temp_radii[j] - 1e-9: + is_valid = False + break + if not is_valid: + break + + if is_valid: + best_sum_radii = current_sum_radii + best_centers = self.centers.copy() + + # Final Polish: Use the precise compute_max_radii on the best found centers + final_radii = compute_max_radii(best_centers) + return best_centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the + GravitationalGrower class. + """ + packer = GravitationalGrower(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4599336971032eb58137bc5a58bb824422e63a53 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..84b0417d493945d43504a3e786b6f6a609f82be9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/edit.diff @@ -0,0 +1,195 @@ +--- a/original.py ++++ b/original.py +@@ -1,149 +1,172 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + # This function remains the same as it is a robust way to evaluate a given center configuration. + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + # This ensures the ratio of radii is maintained if possible + # while eliminating overlap. + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using an iterative + local search algorithm with targeted perturbations and greedy acceptance, + starting from an asymmetric Gaussian-deformed grid. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Initial Grid Generation (same as previous, provides a good starting point) + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + initial_centers = np.clip(initial_centers, 0.0, 1.0) + +- # 2. Iterative Local Search Optimization ++ # 2. Iterative Local Search with Simulated Annealing ++ # SA is reintroduced to escape local optima, a clear issue in greedy approaches. ++ # The greedy search gets stuck in suboptimal configurations like the central cluster. + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + +- # Main parameters for the local search +- total_iterations = 8000 # Increased iterations for thorough search +- initial_perturb_strength = 0.02 # Initial maximum perturbation for a circle (exploration) +- final_perturb_strength = 0.0005 # Final minimum perturbation for fine-tuning (refinement) ++ # SA requires tracking the current state, which can temporarily worsen. ++ current_centers = initial_centers.copy() ++ current_radii = best_radii.copy() ++ current_sum_radii = best_sum_radii + +- # We use a cache for radii to save computation, re-calculating full radii less often +- # The `best_radii` is used for selection probability calculation ++ # Parameters inspired by high-scoring previous attempts, tuned for more exploration. ++ total_iterations = 15000 # Increased iterations for more thorough search ++ initial_perturb_strength = 0.03 # Increased for more exploration ++ final_perturb_strength = 0.0005 # For fine-tuning ++ ++ # SA Temperature Schedule ++ T_initial = 0.1 # Higher temperature to accept more worse moves early on ++ T_final = 1e-6 # Very low final temperature for greedy-like refinement + + for iteration in range(total_iterations): +- # Linearly decay perturbation strength over iterations ++ # Linearly decay perturbation strength + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + +- candidate_centers = best_centers.copy() ++ # Exponentially decay temperature ++ temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + +- # Target circles that are currently small (more likely to be stuck). +- # This biases the search towards improving less optimized parts of the packing +- # Calculate inverse radii, normalize to get probabilities +- # Add a small constant to avoid division by zero for radius 0 +- inverse_radii = 1 / (best_radii + 1e-8) # Using best_radii from previous best state ++ # Perturb from the current state, not the best state, to explore ++ candidate_centers = current_centers.copy() ++ ++ # Target circles based on the current radii to guide the ongoing search ++ inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + +- # Greedy acceptance: if the new configuration is better, accept it +- if candidate_sum_radii > best_sum_radii: +- best_sum_radii = candidate_sum_radii +- best_centers = candidate_centers.copy() +- best_radii = candidate_radii.copy() # Update best_radii for future selection probabilities +- # print(f"Iter {iteration}: New best sum of radii: {best_sum_radii:.4f}") # For debugging ++ # Simulated Annealing acceptance criteria ++ if candidate_sum_radii > current_sum_radii: ++ # Always accept a better solution ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers.copy() ++ current_radii = candidate_radii.copy() ++ else: ++ # Accept a worse solution with a probability dependent on temperature ++ delta = candidate_sum_radii - current_sum_radii # This is negative ++ if temperature > 1e-9: # Avoid division by zero ++ acceptance_prob = np.exp(delta / temperature) ++ if np.random.rand() < acceptance_prob: ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers.copy() ++ current_radii = candidate_radii.copy() + ++ # Update the globally best solution found so far ++ if current_sum_radii > best_sum_radii: ++ best_sum_radii = current_sum_radii ++ best_centers = current_centers.copy() ++ best_radii = current_radii.copy() + + return best_centers, best_radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/main.py new file mode 100644 index 0000000000000000000000000000000000000000..e7f066029f7b52df33627e0e63f4a039544735a0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/main.py @@ -0,0 +1,172 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + +# This function remains the same as it is a robust way to evaluate a given center configuration. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + # This ensures the ratio of radii is maintained if possible + # while eliminating overlap. + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using an iterative + local search algorithm with targeted perturbations and greedy acceptance, + starting from an asymmetric Gaussian-deformed grid. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Initial Grid Generation (same as previous, provides a good starting point) + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + initial_centers = np.clip(initial_centers, 0.0, 1.0) + + # 2. Iterative Local Search with Simulated Annealing + # SA is reintroduced to escape local optima, a clear issue in greedy approaches. + # The greedy search gets stuck in suboptimal configurations like the central cluster. + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + # SA requires tracking the current state, which can temporarily worsen. + current_centers = initial_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Parameters inspired by high-scoring previous attempts, tuned for more exploration. + total_iterations = 15000 # Increased iterations for more thorough search + initial_perturb_strength = 0.03 # Increased for more exploration + final_perturb_strength = 0.0005 # For fine-tuning + + # SA Temperature Schedule + T_initial = 0.1 # Higher temperature to accept more worse moves early on + T_final = 1e-6 # Very low final temperature for greedy-like refinement + + for iteration in range(total_iterations): + # Linearly decay perturbation strength + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + # Exponentially decay temperature + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + # Perturb from the current state, not the best state, to explore + candidate_centers = current_centers.copy() + + # Target circles based on the current radii to guide the ongoing search + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + if candidate_sum_radii > current_sum_radii: + # Always accept a better solution + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + else: + # Accept a worse solution with a probability dependent on temperature + delta = candidate_sum_radii - current_sum_radii # This is negative + if temperature > 1e-9: # Avoid division by zero + acceptance_prob = np.exp(delta / temperature) + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + + # Update the globally best solution found so far + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/original.py new file mode 100644 index 0000000000000000000000000000000000000000..4b5ecc675357c152be0d6acf123691a32243eef1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/original.py @@ -0,0 +1,149 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + +# This function remains the same as it is a robust way to evaluate a given center configuration. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + # This ensures the ratio of radii is maintained if possible + # while eliminating overlap. + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using an iterative + local search algorithm with targeted perturbations and greedy acceptance, + starting from an asymmetric Gaussian-deformed grid. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Initial Grid Generation (same as previous, provides a good starting point) + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + initial_centers = np.clip(initial_centers, 0.0, 1.0) + + # 2. Iterative Local Search Optimization + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + # Main parameters for the local search + total_iterations = 8000 # Increased iterations for thorough search + initial_perturb_strength = 0.02 # Initial maximum perturbation for a circle (exploration) + final_perturb_strength = 0.0005 # Final minimum perturbation for fine-tuning (refinement) + + # We use a cache for radii to save computation, re-calculating full radii less often + # The `best_radii` is used for selection probability calculation + + for iteration in range(total_iterations): + # Linearly decay perturbation strength over iterations + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + candidate_centers = best_centers.copy() + + # Target circles that are currently small (more likely to be stuck). + # This biases the search towards improving less optimized parts of the packing + # Calculate inverse radii, normalize to get probabilities + # Add a small constant to avoid division by zero for radius 0 + inverse_radii = 1 / (best_radii + 1e-8) # Using best_radii from previous best state + selection_probs = inverse_radii / np.sum(inverse_radii) + + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Greedy acceptance: if the new configuration is better, accept it + if candidate_sum_radii > best_sum_radii: + best_sum_radii = candidate_sum_radii + best_centers = candidate_centers.copy() + best_radii = candidate_radii.copy() # Update best_radii for future selection probabilities + # print(f"Iter {iteration}: New best sum of radii: {best_sum_radii:.4f}") # For debugging + + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..866e64af3619f3053504036349f6fb6a0da70306 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_149/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_149/results +Run 1/1 completed in 32.22 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.291262219856103 + public: {'centers_str': ' centers[0] = (0.3493, 0.2984)\n centers[1] = (0.5115, 0.0941)\n centers[2] = (0.6682, 0.4947)\n centers[3] = (0.8045, 0.2907)\n centers[4] = (0.8968, 0.1031)\n centers[5] = (0.0728, 0.2840)\n centers[6] = (0.2150, 0.3652)\n centers[7] = (0.5147, 0.7478)\n centers[8] = (0.6831, 0.1095)\n centers[9] = (0.9370, 0.3986)\n centers[10] = (0.2634, 0.9343)\n centers[11] = (0.4038, 0.4995)\n centers[12] = (0.5864, 0.4262)\n centers[13] = (0.5110, 0.2563)\n centers[14] = (0.7271, 0.4485)\n centers[15] = (0.1661, 0.5332)\n centers[16] = (0.2922, 0.7457)\n centers[17] = (0.7241, 0.8491)\n centers[18] = (0.6389, 0.6017)\n centers[19] = (0.8733, 0.5769)\n centers[20] = (0.0821, 0.7137)\n centers[21] = (0.1032, 0.8975)\n centers[22] = (0.4433, 0.9078)\n centers[23] = (0.9289, 0.7668)\n centers[24] = (0.9296, 0.9271)\n centers[25] = (0.2630, 0.1566)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.291262219856103} + visualization_path: + execution_time_mean: 32.21622119797394 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..345262dbd1c008a173885ac7aba1ba0f38997692 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.291262219856103, + "public": { + "centers_str": " centers[0] = (0.3493, 0.2984)\n centers[1] = (0.5115, 0.0941)\n centers[2] = (0.6682, 0.4947)\n centers[3] = (0.8045, 0.2907)\n centers[4] = (0.8968, 0.1031)\n centers[5] = (0.0728, 0.2840)\n centers[6] = (0.2150, 0.3652)\n centers[7] = (0.5147, 0.7478)\n centers[8] = (0.6831, 0.1095)\n centers[9] = (0.9370, 0.3986)\n centers[10] = (0.2634, 0.9343)\n centers[11] = (0.4038, 0.4995)\n centers[12] = (0.5864, 0.4262)\n centers[13] = (0.5110, 0.2563)\n centers[14] = (0.7271, 0.4485)\n centers[15] = (0.1661, 0.5332)\n centers[16] = (0.2922, 0.7457)\n centers[17] = (0.7241, 0.8491)\n centers[18] = (0.6389, 0.6017)\n centers[19] = (0.8733, 0.5769)\n centers[20] = (0.0821, 0.7137)\n centers[21] = (0.1032, 0.8975)\n centers[22] = (0.4433, 0.9078)\n centers[23] = (0.9289, 0.7668)\n centers[24] = (0.9296, 0.9271)\n centers[25] = (0.2630, 0.1566)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.291262219856103 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_149/results/packing_viz.png", + "execution_time_mean": 32.21622119797394, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..d089896b630fa7f1607d7f3677b20211056562e0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_149/search_replace.txt @@ -0,0 +1,138 @@ + +reintroduce_simulated_annealing + + +The current greedy algorithm gets stuck in local optima, as evidenced by the inefficient central cluster in the visualization where several small circles are trapped by a larger one. The structure is too rigid, a classic sign of a failed hill-climbing search. + +To address this, I am re-introducing Simulated Annealing (SA), a powerful optimization technique that was successful in previous high-scoring versions of this program. SA allows the search to temporarily accept "worse" solutions (those with a smaller sum of radii) with a probability that decreases over time. This enables the algorithm to escape local optima and explore the solution space more thoroughly, leading to better global solutions. + +This change involves: +1. Replacing the greedy search with an SA loop that tracks both `current` and `best` solutions. +2. Introducing an exponential temperature decay schedule (`T_initial` to `T_final`). +3. Updating the search to explore from the `current` state, not always the `best` one. +4. Increasing the total number of iterations to `15000` to give the annealing process sufficient time to converge. + + +<<<<<<< SEARCH + # 2. Iterative Local Search Optimization + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + # Main parameters for the local search + total_iterations = 8000 # Increased iterations for thorough search + initial_perturb_strength = 0.02 # Initial maximum perturbation for a circle (exploration) + final_perturb_strength = 0.0005 # Final minimum perturbation for fine-tuning (refinement) + + # We use a cache for radii to save computation, re-calculating full radii less often + # The `best_radii` is used for selection probability calculation + + for iteration in range(total_iterations): + # Linearly decay perturbation strength over iterations + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + candidate_centers = best_centers.copy() + + # Target circles that are currently small (more likely to be stuck). + # This biases the search towards improving less optimized parts of the packing + # Calculate inverse radii, normalize to get probabilities + # Add a small constant to avoid division by zero for radius 0 + inverse_radii = 1 / (best_radii + 1e-8) # Using best_radii from previous best state + selection_probs = inverse_radii / np.sum(inverse_radii) + + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Greedy acceptance: if the new configuration is better, accept it + if candidate_sum_radii > best_sum_radii: + best_sum_radii = candidate_sum_radii + best_centers = candidate_centers.copy() + best_radii = candidate_radii.copy() # Update best_radii for future selection probabilities + # print(f"Iter {iteration}: New best sum of radii: {best_sum_radii:.4f}") # For debugging + + + return best_centers, best_radii +======= + # 2. Iterative Local Search with Simulated Annealing + # SA is reintroduced to escape local optima, a clear issue in greedy approaches. + # The greedy search gets stuck in suboptimal configurations like the central cluster. + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + # SA requires tracking the current state, which can temporarily worsen. + current_centers = initial_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Parameters inspired by high-scoring previous attempts, tuned for more exploration. + total_iterations = 15000 # Increased iterations for more thorough search + initial_perturb_strength = 0.03 # Increased for more exploration + final_perturb_strength = 0.0005 # For fine-tuning + + # SA Temperature Schedule + T_initial = 0.1 # Higher temperature to accept more worse moves early on + T_final = 1e-6 # Very low final temperature for greedy-like refinement + + for iteration in range(total_iterations): + # Linearly decay perturbation strength + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + # Exponentially decay temperature + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + # Perturb from the current state, not the best state, to explore + candidate_centers = current_centers.copy() + + # Target circles based on the current radii to guide the ongoing search + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + if candidate_sum_radii > current_sum_radii: + # Always accept a better solution + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + else: + # Accept a worse solution with a probability dependent on temperature + delta = candidate_sum_radii - current_sum_radii # This is negative + if temperature > 1e-9: # Avoid division by zero + acceptance_prob = np.exp(delta / temperature) + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + + # Update the globally best solution found so far + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + return best_centers, best_radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e8748374a985e016442ec440a5d0bf6bb2175ee Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..fed8ed872cdc98fb2753a1356dbac0980b0d37c3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/edit.diff @@ -0,0 +1,510 @@ +--- a/original.py ++++ b/original.py +@@ -1,348 +1,214 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + +-# compute_max_radii remains unchanged as it's a robust evaluation function. ++# compute_max_radii remains a robust evaluation function. + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. +- +- Args: +- centers: np.array of shape (n, 2) with (x, y) coordinates +- +- Returns: +- np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] +- +- # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +-class CirclePacker: +- """ +- A class to encapsulate the state and logic for packing circles using +- a hybrid approach: initial aggressive perturbation, a quick force-directed +- relaxation, and then a primary optimization via simulated annealing. +- +- This structure aims to combine the benefits of force-directed methods +- (quick stabilization) with metaheuristics (escaping local optima). +- """ +- +- def __init__(self, n=26): +- """Initializes the packer with the number of circles.""" ++class MemeticPacker: ++ """ ++ Implements a Memetic Algorithm for the circle packing problem. ++ This combines a Genetic Algorithm for global search with a local ++ search method (Force-Directed Relaxation) for refinement. ++ """ ++ def __init__(self, n, pop_size=30, generations=150, tournament_k=3, ++ mutation_rate=0.4, mutation_strength=0.05): + self.n = n +- self.centers = np.zeros((n, 2)) +- +- def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): +- """ +- Generates an initial configuration by creating a base 5x5 grid, +- aggressively deforming it to create a void, and placing the 26th circle. +- The deformation helps break the initial grid symmetry. +- """ +- # Start with a 5x5 grid for the first 25 circles. ++ self.pop_size = pop_size ++ self.generations = generations ++ self.tournament_k = tournament_k ++ self.mutation_rate = mutation_rate ++ self.mutation_strength = mutation_strength ++ self.population = [] # List of dicts: {'centers': array, 'fitness': float} ++ ++ def _fitness(self, centers): ++ """Fitness is the sum of radii.""" ++ return np.sum(compute_max_radii(centers)) ++ ++ def _force_directed_relaxation(self, centers, iters, step_size, repulsion_strength, ++ boundary_strength, repulsion_threshold, boundary_margin): ++ """A vectorized local search method to refine a solution.""" ++ current_centers = centers.copy() ++ for _ in range(iters): ++ diff = current_centers[:, np.newaxis, :] - current_centers[np.newaxis, :, :] ++ dists = np.linalg.norm(diff, axis=2) ++ mask = (dists > 1e-9) & (dists < repulsion_threshold) ++ force_scalar = np.zeros_like(dists) ++ force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] ++ force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ forces = np.sum(force_vectors, axis=1) ++ ++ forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - current_centers[:, 0]) ++ forces[:, 0] -= boundary_strength * np.maximum(0, current_centers[:, 0] - (1 - boundary_margin)) ++ forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - current_centers[:, 1]) ++ forces[:, 1] -= boundary_strength * np.maximum(0, current_centers[:, 1] - (1 - boundary_margin)) ++ ++ current_centers += step_size * forces ++ current_centers = np.clip(current_centers, 0.0, 1.0) ++ return current_centers ++ ++ def _initialize_population(self): ++ """Create a diverse initial population.""" ++ initial_configs = [] ++ # Config 1: Deformed grid + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # Vectorized Gaussian push to create the void. +- displacements = base_centers_25 - void_center +- distances = np.linalg.norm(displacements, axis=1) +- mask = distances > 1e-9 +- +- push_magnitudes = np.zeros(25) +- push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) +- +- if np.any(mask): +- displacements[mask] /= distances[mask, np.newaxis] +- +- initial_centers = np.zeros((self.n, 2)) +- initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- initial_centers[25] = void_center +- self.centers = np.clip(initial_centers, 0.0, 1.0) +- +- def _force_directed_relaxation(self, iters, step_size, repulsion_strength, +- boundary_strength, repulsion_threshold, boundary_margin): +- """ +- Applies a force-directed relaxation step using vectorized calculations. +- This helps quickly resolve immediate overlaps and stabilize the configuration. +- """ +- for _ in range(iters): +- # Vectorized Circle-Circle Repulsion +- diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] +- dists = np.linalg.norm(diff, axis=2) +- +- mask = (dists > 1e-9) & (dists < repulsion_threshold) +- +- force_scalar = np.zeros_like(dists) +- force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] +- +- # Use np.divide with where clause to handle potential division by zero for diff/dists +- force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +- forces = np.sum(force_vectors, axis=1) +- +- # Vectorized Boundary Repulsion +- forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) +- forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) +- forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) +- forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) +- +- self.centers += step_size * forces +- self.centers = np.clip(self.centers, 0.0, 1.0) +- +- +- def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, +- initial_perturb_strength, final_perturb_strength): +- """ +- Performs a simulated annealing optimization on the circle centers. +- It allows for accepting 'worse' states with a decreasing probability +- to escape local optima. +- """ +- best_centers = self.centers.copy() +- best_radii = compute_max_radii(best_centers) +- best_sum_radii = np.sum(best_radii) +- +- current_centers = self.centers.copy() +- current_radii = best_radii.copy() +- current_sum_radii = best_sum_radii +- +- # Stagnation detection and escape parameters +- no_improvement_count = 0 +- max_no_improvement_steps = 1000 # Iterations without improvement to trigger a boost +- perturb_boost = 1.0 +- boost_factor = 4.0 # A strong, but not excessively disruptive, kick +- boost_decay = 0.95 # Gradual decay of the boost +- +- for iteration in range(total_iterations): +- # Logarithmic decay for temperature and base perturbation strength +- progress = iteration / total_iterations +- temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) +- base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) +- +- # Check for stagnation and apply a temporary perturbation boost +- if no_improvement_count >= max_no_improvement_steps: +- perturb_boost = boost_factor +- no_improvement_count = 0 # Reset counter after triggering boost +- +- # Apply temporary perturbation boost, then decay it +- current_base_perturb_strength_with_boost = base_perturb_strength * perturb_boost +- if perturb_boost > 1.0: +- perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay # Decay towards 1.0 +- +- candidate_centers = current_centers.copy() +- +- # Calculate selection probabilities: prioritize smaller circles AND overlapping circles +- inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero +- inverse_radii_normalized = inverse_radii / np.sum(inverse_radii) +- +- overlap_scores = np.zeros(self.n) +- for i in range(self.n): +- for j in range(i + 1, self.n): +- dist = np.linalg.norm(current_centers[i] - current_centers[j]) +- current_rad_sum = current_radii[i] + current_radii[j] +- if current_rad_sum > dist: # There's an overlap +- overlap_amount = current_rad_sum - dist +- overlap_scores[i] += overlap_amount +- overlap_scores[j] += overlap_amount +- +- # Normalize overlap scores if there are any, otherwise set to zero +- if np.sum(overlap_scores) > 1e-9: +- normalized_overlap_scores = overlap_scores / np.sum(overlap_scores) +- else: +- normalized_overlap_scores = np.zeros(self.n) +- +- # Combine inverse_radii and normalized_overlap_scores for selection +- # Adjust weights: more weight on inverse_radii, but significant weight on overlap +- combined_selection_criteria = (inverse_radii_normalized * 0.6 + normalized_overlap_scores * 0.4) +- # Ensure selection_probs sums to 1. Handle case where all criteria are zero. +- sum_criteria = np.sum(combined_selection_criteria) +- if sum_criteria > 1e-9: +- selection_probs = combined_selection_criteria / sum_criteria +- else: # Fallback to uniform if no specific criteria to follow (e.g., all radii 0, no overlaps) +- selection_probs = np.ones(self.n) / self.n +- +- # Decide between dual rotational and single translational perturbation +- dual_rotational_perturb_prob = 0.20 # Probability of performing a dual rotational perturbation +- +- if np.random.rand() < dual_rotational_perturb_prob: +- # Dual Rotational Perturbation: select two circles and rotate them around their midpoint +- # Select a primary circle based on the combined selection probabilities +- c1_idx = np.random.choice(self.n, p=selection_probs) +- +- # Find the closest neighbor (excluding self) +- distances_to_c1 = np.linalg.norm(current_centers - current_centers[c1_idx], axis=1) +- distances_to_c1[c1_idx] = np.inf # Exclude self +- +- # If no other circle exists or all are at inf, fallback to single perturbation +- if np.min(distances_to_c1) == np.inf: +- # Fallback to single translational perturbation for the primary circle +- circle_idx = c1_idx +- +- # Calculate adaptive perturbation strength +- avg_inverse_radius = np.mean(inverse_radii) +- scale_factor = inverse_radii[circle_idx] / avg_inverse_radius +- effective_perturb_strength = current_base_perturb_strength_with_boost * np.clip(scale_factor, 0.7, 2.5) +- +- # Apply a random displacement +- displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +- candidate_centers[circle_idx] += displacement +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +- else: +- c2_idx = np.argmin(distances_to_c1) # The closest neighbor index +- +- # Calculate adaptive perturbation strength for the rotational angle +- avg_inverse_radius = np.mean(inverse_radii) +- scale_factor_c1 = inverse_radii[c1_idx] / avg_inverse_radius +- effective_perturb_strength_for_angle = current_base_perturb_strength_with_boost * np.clip(scale_factor_c1, 0.7, 2.5) +- +- # Get centers and midpoint +- center1 = candidate_centers[c1_idx] +- center2 = candidate_centers[c2_idx] +- midpoint = (center1 + center2) / 2 +- +- vec_c1_to_mid = center1 - midpoint # Vector from midpoint to center1 +- +- # Rotate by a small random angle. Angle magnitude scaled by effective_perturb_strength +- # Max angle starts at 0.5 radians (approx 28 degrees) and decays with perturb_strength +- max_angle_rad = 0.5 * (effective_perturb_strength_for_angle / initial_perturb_strength) +- angle = np.random.uniform(-max_angle_rad, max_angle_rad) +- +- cos_angle = np.cos(angle) +- sin_angle = np.sin(angle) +- rotation_matrix = np.array([[cos_angle, -sin_angle], [sin_angle, cos_angle]]) +- +- vec_c1_rotated = np.dot(rotation_matrix, vec_c1_to_mid) +- +- candidate_centers[c1_idx] = np.clip(midpoint + vec_c1_rotated, 0.0, 1.0) +- candidate_centers[c2_idx] = np.clip(midpoint - vec_c1_rotated, 0.0, 1.0) # c2 moves opposite to c1 relative to midpoint +- else: +- # Single Circle Translational Perturbation +- circle_idx = np.random.choice(self.n, p=selection_probs) +- +- # Apply adaptive perturbation strength based on the selected circle's inverse radius +- avg_inverse_radius = np.mean(inverse_radii) +- scale_factor = inverse_radii[circle_idx] / avg_inverse_radius +- effective_perturb_strength = current_base_perturb_strength_with_boost * np.clip(scale_factor, 0.7, 2.5) +- +- # Apply a random displacement +- displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +- candidate_centers[circle_idx] += displacement +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +- +- # Evaluate the new configuration +- candidate_radii = compute_max_radii(candidate_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- # Metropolis-Hastings acceptance criterion +- delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better +- if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): +- # Accept the new state +- current_sum_radii = candidate_sum_radii +- current_centers = candidate_centers +- current_radii = candidate_radii +- +- # If this is the best state found so far, save it and reset stagnation counter +- if current_sum_radii > best_sum_radii: +- best_sum_radii = current_sum_radii +- best_centers = current_centers.copy() +- best_radii = current_radii.copy() +- no_improvement_count = 0 +- else: +- no_improvement_count += 1 +- else: +- # Reject the new state +- no_improvement_count += 1 +- +- self.centers = best_centers # Update the class's centers to the best found +- return best_radii # Return best radii for convenience ++ # Generate diverse starting points using different void centers ++ for _ in range(self.pop_size): ++ void_center = np.random.uniform(0.2, 0.8, 2) ++ amplitude = np.random.uniform(0.05, 0.1) ++ sigma = 0.15 ++ displacements = base_centers_25 - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ mask = distances > 1e-9 ++ push_magnitudes = np.zeros(25) ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ if np.any(mask): ++ displacements[mask] /= distances[mask, np.newaxis] ++ ++ candidate_centers = np.zeros((self.n, 2)) ++ candidate_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ candidate_centers[25] = void_center ++ candidate_centers = np.clip(candidate_centers, 0.0, 1.0) ++ initial_configs.append(candidate_centers) ++ ++ for centers in initial_configs: ++ # Refine each initial config with a short local search ++ refined_centers = self._force_directed_relaxation(centers, iters=100, step_size=0.002, repulsion_strength=0.01, ++ boundary_strength=0.05, repulsion_threshold=0.2, boundary_margin=0.05) ++ fitness = self._fitness(refined_centers) ++ self.population.append({'centers': refined_centers, 'fitness': fitness}) ++ ++ def _tournament_selection(self): ++ """Selects an individual using tournament selection.""" ++ best_ind = None ++ for _ in range(self.tournament_k): ++ ind = self.population[np.random.randint(0, self.pop_size)] ++ if best_ind is None or ind['fitness'] > best_ind['fitness']: ++ best_ind = ind ++ return best_ind ++ ++ def _kmeans_crossover(self, parent1, parent2): ++ """Creates a child by running K-Means on the combined parent centers.""" ++ combined_centers = np.vstack((parent1['centers'], parent2['centers'])) ++ ++ # Lightweight K-Means implementation ++ # 1. Initialize centroids by picking k points from the combined set ++ centroids = combined_centers[np.random.choice(2 * self.n, self.n, replace=False)] ++ ++ # 2. Iterate to refine centroids ++ for _ in range(10): # 10 iterations is sufficient for this purpose ++ # Assign points to closest centroid ++ diffs = combined_centers[:, np.newaxis, :] - centroids[np.newaxis, :, :] ++ dists_sq = np.sum(diffs**2, axis=2) ++ assignments = np.argmin(dists_sq, axis=1) ++ ++ # Update centroids to be the mean of their assigned points ++ new_centroids = np.array([combined_centers[assignments == k].mean(axis=0) for k in range(self.n)]) ++ # Handle empty clusters by not updating their centroid ++ for k in range(self.n): ++ if np.any(assignments == k): ++ centroids[k] = new_centroids[k] ++ ++ return np.clip(centroids, 0.0, 1.0) ++ ++ def _mutate(self, centers): ++ """Applies a random perturbation to a single circle.""" ++ mutated_centers = centers.copy() ++ ++ # Select a circle to mutate, prioritizing smaller ones ++ radii = compute_max_radii(mutated_centers) ++ inverse_radii = 1.0 / (radii + 1e-8) ++ probs = inverse_radii / np.sum(inverse_radii) ++ idx_to_mutate = np.random.choice(self.n, p=probs) ++ ++ # Apply mutation ++ displacement = np.random.uniform(-self.mutation_strength, self.mutation_strength, 2) ++ mutated_centers[idx_to_mutate] += displacement ++ mutated_centers[idx_to_mutate] = np.clip(mutated_centers[idx_to_mutate], 0.0, 1.0) ++ ++ return mutated_centers + + def pack(self): +- """ +- Orchestrates the entire packing process: +- 1. Aggressive initial placement with a central void. +- 2. A short, vectorized force-directed relaxation to quickly stabilize. +- 3. A primary optimization phase using simulated annealing local search. +- 4. A final gentle force-directed relaxation for polish. +- """ +- # 1. Aggressive initial placement with a *randomized* void center +- # Restrict void_center to central region to allow for more diverse starting patterns. +- random_void_center = np.random.uniform(0.3, 0.7, 2) +- self._initial_placement_with_void_and_perturbation( +- void_center=random_void_center, # Use randomized void center +- amplitude=0.08, # Increased amplitude for stronger initial push to break grid +- sigma=0.15 +- ) +- +- # 2. Short, aggressive force-directed relaxation to resolve immediate chaos +- self._force_directed_relaxation( +- iters=500, # More iterations for initial cleanup +- step_size=0.002, +- repulsion_strength=0.02, +- boundary_strength=0.08, +- repulsion_threshold=0.19, +- boundary_margin=0.04 +- ) +- +- # 3. Simulated Annealing Local Search for global optimization +- self._simulated_annealing_local_search( +- total_iterations=18000, # Further increased iterations for thorough SA search with new perturbation strategy +- initial_temp=0.0007, # Slightly higher initial temp +- final_temp=1e-9, # Slightly lower final temp +- initial_perturb_strength=0.03, # Slightly larger initial perturbation +- final_perturb_strength=0.0001 +- ) +- +- # 4. After SA, apply one final gentle relaxation to ensure local stability +- # and resolve any tiny remaining overlaps or improve boundary contact. +- self._force_directed_relaxation( +- iters=300, +- step_size=0.0001, +- repulsion_strength=0.001, +- boundary_strength=0.005, +- repulsion_threshold=0.18, +- boundary_margin=0.02 +- ) +- +- # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. +- final_radii = compute_max_radii(self.centers) +- +- return self.centers, final_radii ++ """Main evolutionary loop.""" ++ self._initialize_population() ++ ++ for gen in range(self.generations): ++ parent1 = self._tournament_selection() ++ parent2 = self._tournament_selection() ++ ++ child_centers = self._kmeans_crossover(parent1, parent2) ++ ++ if np.random.rand() < self.mutation_rate: ++ child_centers = self._mutate(child_centers) ++ ++ # Local search (meme) on the new child ++ child_centers = self._force_directed_relaxation(child_centers, iters=80, step_size=0.001, repulsion_strength=0.005, ++ boundary_strength=0.02, repulsion_threshold=0.18, boundary_margin=0.03) ++ child_fitness = self._fitness(child_centers) ++ ++ # Find the worst individual to replace ++ worst_idx = min(range(self.pop_size), key=lambda i: self.population[i]['fitness']) ++ ++ # Elitist replacement: replace if better than the worst ++ if child_fitness > self.population[worst_idx]['fitness']: ++ self.population[worst_idx] = {'centers': child_centers, 'fitness': child_fitness} ++ ++ # Return the best individual from the final population ++ best_idx = max(range(self.pop_size), key=lambda i: self.population[i]['fitness']) ++ best_centers = self.population[best_idx]['centers'] ++ ++ # Final polish on the best result ++ final_centers = self._force_directed_relaxation(best_centers, iters=400, step_size=0.0001, repulsion_strength=0.001, ++ boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.01) ++ ++ final_radii = compute_max_radii(final_centers) ++ return final_centers, final_radii + + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles using the CirclePacker class. +- """ +- packer = CirclePacker(n=26) ++ Constructs a high-density arrangement of 26 circles using the MemeticPacker. ++ """ ++ n = 26 ++ packer = MemeticPacker(n=n, pop_size=40, generations=200, mutation_rate=0.5) + centers, radii = packer.pack() + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/main.py new file mode 100644 index 0000000000000000000000000000000000000000..39ebb7dbeeaeb36794940c34ce306bca994f914c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/main.py @@ -0,0 +1,214 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class MemeticPacker: + """ + Implements a Memetic Algorithm for the circle packing problem. + This combines a Genetic Algorithm for global search with a local + search method (Force-Directed Relaxation) for refinement. + """ + def __init__(self, n, pop_size=30, generations=150, tournament_k=3, + mutation_rate=0.4, mutation_strength=0.05): + self.n = n + self.pop_size = pop_size + self.generations = generations + self.tournament_k = tournament_k + self.mutation_rate = mutation_rate + self.mutation_strength = mutation_strength + self.population = [] # List of dicts: {'centers': array, 'fitness': float} + + def _fitness(self, centers): + """Fitness is the sum of radii.""" + return np.sum(compute_max_radii(centers)) + + def _force_directed_relaxation(self, centers, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """A vectorized local search method to refine a solution.""" + current_centers = centers.copy() + for _ in range(iters): + diff = current_centers[:, np.newaxis, :] - current_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + mask = (dists > 1e-9) & (dists < repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - current_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, current_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - current_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, current_centers[:, 1] - (1 - boundary_margin)) + + current_centers += step_size * forces + current_centers = np.clip(current_centers, 0.0, 1.0) + return current_centers + + def _initialize_population(self): + """Create a diverse initial population.""" + initial_configs = [] + # Config 1: Deformed grid + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Generate diverse starting points using different void centers + for _ in range(self.pop_size): + void_center = np.random.uniform(0.2, 0.8, 2) + amplitude = np.random.uniform(0.05, 0.1) + sigma = 0.15 + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + candidate_centers = np.zeros((self.n, 2)) + candidate_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + candidate_centers[25] = void_center + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + initial_configs.append(candidate_centers) + + for centers in initial_configs: + # Refine each initial config with a short local search + refined_centers = self._force_directed_relaxation(centers, iters=100, step_size=0.002, repulsion_strength=0.01, + boundary_strength=0.05, repulsion_threshold=0.2, boundary_margin=0.05) + fitness = self._fitness(refined_centers) + self.population.append({'centers': refined_centers, 'fitness': fitness}) + + def _tournament_selection(self): + """Selects an individual using tournament selection.""" + best_ind = None + for _ in range(self.tournament_k): + ind = self.population[np.random.randint(0, self.pop_size)] + if best_ind is None or ind['fitness'] > best_ind['fitness']: + best_ind = ind + return best_ind + + def _kmeans_crossover(self, parent1, parent2): + """Creates a child by running K-Means on the combined parent centers.""" + combined_centers = np.vstack((parent1['centers'], parent2['centers'])) + + # Lightweight K-Means implementation + # 1. Initialize centroids by picking k points from the combined set + centroids = combined_centers[np.random.choice(2 * self.n, self.n, replace=False)] + + # 2. Iterate to refine centroids + for _ in range(10): # 10 iterations is sufficient for this purpose + # Assign points to closest centroid + diffs = combined_centers[:, np.newaxis, :] - centroids[np.newaxis, :, :] + dists_sq = np.sum(diffs**2, axis=2) + assignments = np.argmin(dists_sq, axis=1) + + # Update centroids to be the mean of their assigned points + new_centroids = np.array([combined_centers[assignments == k].mean(axis=0) for k in range(self.n)]) + # Handle empty clusters by not updating their centroid + for k in range(self.n): + if np.any(assignments == k): + centroids[k] = new_centroids[k] + + return np.clip(centroids, 0.0, 1.0) + + def _mutate(self, centers): + """Applies a random perturbation to a single circle.""" + mutated_centers = centers.copy() + + # Select a circle to mutate, prioritizing smaller ones + radii = compute_max_radii(mutated_centers) + inverse_radii = 1.0 / (radii + 1e-8) + probs = inverse_radii / np.sum(inverse_radii) + idx_to_mutate = np.random.choice(self.n, p=probs) + + # Apply mutation + displacement = np.random.uniform(-self.mutation_strength, self.mutation_strength, 2) + mutated_centers[idx_to_mutate] += displacement + mutated_centers[idx_to_mutate] = np.clip(mutated_centers[idx_to_mutate], 0.0, 1.0) + + return mutated_centers + + def pack(self): + """Main evolutionary loop.""" + self._initialize_population() + + for gen in range(self.generations): + parent1 = self._tournament_selection() + parent2 = self._tournament_selection() + + child_centers = self._kmeans_crossover(parent1, parent2) + + if np.random.rand() < self.mutation_rate: + child_centers = self._mutate(child_centers) + + # Local search (meme) on the new child + child_centers = self._force_directed_relaxation(child_centers, iters=80, step_size=0.001, repulsion_strength=0.005, + boundary_strength=0.02, repulsion_threshold=0.18, boundary_margin=0.03) + child_fitness = self._fitness(child_centers) + + # Find the worst individual to replace + worst_idx = min(range(self.pop_size), key=lambda i: self.population[i]['fitness']) + + # Elitist replacement: replace if better than the worst + if child_fitness > self.population[worst_idx]['fitness']: + self.population[worst_idx] = {'centers': child_centers, 'fitness': child_fitness} + + # Return the best individual from the final population + best_idx = max(range(self.pop_size), key=lambda i: self.population[i]['fitness']) + best_centers = self.population[best_idx]['centers'] + + # Final polish on the best result + final_centers = self._force_directed_relaxation(best_centers, iters=400, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.01) + + final_radii = compute_max_radii(final_centers) + return final_centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the MemeticPacker. + """ + n = 26 + packer = MemeticPacker(n=n, pop_size=40, generations=200, mutation_rate=0.5) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/original.py new file mode 100644 index 0000000000000000000000000000000000000000..b09bb9fcb38044d6ec941691c2a5f315d3812984 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/original.py @@ -0,0 +1,348 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Use np.divide with where clause to handle potential division by zero for diff/dists + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_local_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = self.centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Stagnation detection and escape parameters + no_improvement_count = 0 + max_no_improvement_steps = 1000 # Iterations without improvement to trigger a boost + perturb_boost = 1.0 + boost_factor = 4.0 # A strong, but not excessively disruptive, kick + boost_decay = 0.95 # Gradual decay of the boost + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and base perturbation strength + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Check for stagnation and apply a temporary perturbation boost + if no_improvement_count >= max_no_improvement_steps: + perturb_boost = boost_factor + no_improvement_count = 0 # Reset counter after triggering boost + + # Apply temporary perturbation boost, then decay it + current_base_perturb_strength_with_boost = base_perturb_strength * perturb_boost + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay # Decay towards 1.0 + + candidate_centers = current_centers.copy() + + # Calculate selection probabilities: prioritize smaller circles AND overlapping circles + inverse_radii = 1 / (current_radii + 1e-8) # Add small constant to avoid div by zero + inverse_radii_normalized = inverse_radii / np.sum(inverse_radii) + + overlap_scores = np.zeros(self.n) + for i in range(self.n): + for j in range(i + 1, self.n): + dist = np.linalg.norm(current_centers[i] - current_centers[j]) + current_rad_sum = current_radii[i] + current_radii[j] + if current_rad_sum > dist: # There's an overlap + overlap_amount = current_rad_sum - dist + overlap_scores[i] += overlap_amount + overlap_scores[j] += overlap_amount + + # Normalize overlap scores if there are any, otherwise set to zero + if np.sum(overlap_scores) > 1e-9: + normalized_overlap_scores = overlap_scores / np.sum(overlap_scores) + else: + normalized_overlap_scores = np.zeros(self.n) + + # Combine inverse_radii and normalized_overlap_scores for selection + # Adjust weights: more weight on inverse_radii, but significant weight on overlap + combined_selection_criteria = (inverse_radii_normalized * 0.6 + normalized_overlap_scores * 0.4) + # Ensure selection_probs sums to 1. Handle case where all criteria are zero. + sum_criteria = np.sum(combined_selection_criteria) + if sum_criteria > 1e-9: + selection_probs = combined_selection_criteria / sum_criteria + else: # Fallback to uniform if no specific criteria to follow (e.g., all radii 0, no overlaps) + selection_probs = np.ones(self.n) / self.n + + # Decide between dual rotational and single translational perturbation + dual_rotational_perturb_prob = 0.20 # Probability of performing a dual rotational perturbation + + if np.random.rand() < dual_rotational_perturb_prob: + # Dual Rotational Perturbation: select two circles and rotate them around their midpoint + # Select a primary circle based on the combined selection probabilities + c1_idx = np.random.choice(self.n, p=selection_probs) + + # Find the closest neighbor (excluding self) + distances_to_c1 = np.linalg.norm(current_centers - current_centers[c1_idx], axis=1) + distances_to_c1[c1_idx] = np.inf # Exclude self + + # If no other circle exists or all are at inf, fallback to single perturbation + if np.min(distances_to_c1) == np.inf: + # Fallback to single translational perturbation for the primary circle + circle_idx = c1_idx + + # Calculate adaptive perturbation strength + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = current_base_perturb_strength_with_boost * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + else: + c2_idx = np.argmin(distances_to_c1) # The closest neighbor index + + # Calculate adaptive perturbation strength for the rotational angle + avg_inverse_radius = np.mean(inverse_radii) + scale_factor_c1 = inverse_radii[c1_idx] / avg_inverse_radius + effective_perturb_strength_for_angle = current_base_perturb_strength_with_boost * np.clip(scale_factor_c1, 0.7, 2.5) + + # Get centers and midpoint + center1 = candidate_centers[c1_idx] + center2 = candidate_centers[c2_idx] + midpoint = (center1 + center2) / 2 + + vec_c1_to_mid = center1 - midpoint # Vector from midpoint to center1 + + # Rotate by a small random angle. Angle magnitude scaled by effective_perturb_strength + # Max angle starts at 0.5 radians (approx 28 degrees) and decays with perturb_strength + max_angle_rad = 0.5 * (effective_perturb_strength_for_angle / initial_perturb_strength) + angle = np.random.uniform(-max_angle_rad, max_angle_rad) + + cos_angle = np.cos(angle) + sin_angle = np.sin(angle) + rotation_matrix = np.array([[cos_angle, -sin_angle], [sin_angle, cos_angle]]) + + vec_c1_rotated = np.dot(rotation_matrix, vec_c1_to_mid) + + candidate_centers[c1_idx] = np.clip(midpoint + vec_c1_rotated, 0.0, 1.0) + candidate_centers[c2_idx] = np.clip(midpoint - vec_c1_rotated, 0.0, 1.0) # c2 moves opposite to c1 relative to midpoint + else: + # Single Circle Translational Perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = current_base_perturb_strength_with_boost * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it and reset stagnation counter + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + else: + # Reject the new state + no_improvement_count += 1 + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_local_search( + total_iterations=18000, # Further increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..0c757bb999a50fc03c9a21213dd55ae94a40a5ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/job_log.err @@ -0,0 +1,15 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_151/main.py:63: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_151/main.py:135: RuntimeWarning: Mean of empty slice + new_centroids = np.array([combined_centers[assignments == k].mean(axis=0) for k in range(self.n)]) +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/numpy/_core/_methods.py:134: RuntimeWarning: invalid value encountered in divide + ret = um.true_divide( diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..064007c16dad6a2a73115321aaa2786ac29a7898 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_151/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_151/results +Run 1/1 completed in 4.47 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9611821138600856 + public: {'centers_str': ' centers[0] = (0.4988, 0.9009)\n centers[1] = (0.7008, 0.7292)\n centers[2] = (0.2167, 0.9001)\n centers[3] = (0.4967, 0.7053)\n centers[4] = (0.0972, 0.0980)\n centers[5] = (0.6406, 0.3296)\n centers[6] = (0.2994, 0.7034)\n centers[7] = (0.3268, 0.2769)\n centers[8] = (0.0910, 0.2985)\n centers[9] = (0.9004, 0.0994)\n centers[10] = (0.3366, 0.4782)\n centers[11] = (0.6866, 0.9159)\n centers[12] = (0.9047, 0.2974)\n centers[13] = (0.0942, 0.5030)\n centers[14] = (0.0995, 0.7341)\n centers[15] = (0.7093, 0.5075)\n centers[16] = (0.9000, 0.9001)\n centers[17] = (0.9069, 0.5018)\n centers[18] = (0.5387, 0.8774)\n centers[19] = (0.5209, 0.2887)\n centers[20] = (0.7068, 0.1599)\n centers[21] = (0.5040, 0.0940)\n centers[22] = (0.5514, 0.7007)\n centers[23] = (0.2972, 0.0882)\n centers[24] = (0.5178, 0.5121)\n centers[25] = (0.9011, 0.7013)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9611821138600856} + visualization_path: + execution_time_mean: 4.473999687004834 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..329cc388597e901ebc1787fd42bba29bf8d0579a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9611821138600856, + "public": { + "centers_str": " centers[0] = (0.4988, 0.9009)\n centers[1] = (0.7008, 0.7292)\n centers[2] = (0.2167, 0.9001)\n centers[3] = (0.4967, 0.7053)\n centers[4] = (0.0972, 0.0980)\n centers[5] = (0.6406, 0.3296)\n centers[6] = (0.2994, 0.7034)\n centers[7] = (0.3268, 0.2769)\n centers[8] = (0.0910, 0.2985)\n centers[9] = (0.9004, 0.0994)\n centers[10] = (0.3366, 0.4782)\n centers[11] = (0.6866, 0.9159)\n centers[12] = (0.9047, 0.2974)\n centers[13] = (0.0942, 0.5030)\n centers[14] = (0.0995, 0.7341)\n centers[15] = (0.7093, 0.5075)\n centers[16] = (0.9000, 0.9001)\n centers[17] = (0.9069, 0.5018)\n centers[18] = (0.5387, 0.8774)\n centers[19] = (0.5209, 0.2887)\n centers[20] = (0.7068, 0.1599)\n centers[21] = (0.5040, 0.0940)\n centers[22] = (0.5514, 0.7007)\n centers[23] = (0.2972, 0.0882)\n centers[24] = (0.5178, 0.5121)\n centers[25] = (0.9011, 0.7013)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9611821138600856 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_151/results/packing_viz.png", + "execution_time_mean": 4.473999687004834, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a82092494bdfceb48a2e5e86dd442dd9c3e56d7 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_151/rewrite.txt @@ -0,0 +1,205 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class MemeticPacker: + """ + Implements a Memetic Algorithm for the circle packing problem. + This combines a Genetic Algorithm for global search with a local + search method (Force-Directed Relaxation) for refinement. + """ + def __init__(self, n, pop_size=30, generations=150, tournament_k=3, + mutation_rate=0.4, mutation_strength=0.05): + self.n = n + self.pop_size = pop_size + self.generations = generations + self.tournament_k = tournament_k + self.mutation_rate = mutation_rate + self.mutation_strength = mutation_strength + self.population = [] # List of dicts: {'centers': array, 'fitness': float} + + def _fitness(self, centers): + """Fitness is the sum of radii.""" + return np.sum(compute_max_radii(centers)) + + def _force_directed_relaxation(self, centers, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """A vectorized local search method to refine a solution.""" + current_centers = centers.copy() + for _ in range(iters): + diff = current_centers[:, np.newaxis, :] - current_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + mask = (dists > 1e-9) & (dists < repulsion_threshold) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - current_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, current_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - current_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, current_centers[:, 1] - (1 - boundary_margin)) + + current_centers += step_size * forces + current_centers = np.clip(current_centers, 0.0, 1.0) + return current_centers + + def _initialize_population(self): + """Create a diverse initial population.""" + initial_configs = [] + # Config 1: Deformed grid + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Generate diverse starting points using different void centers + for _ in range(self.pop_size): + void_center = np.random.uniform(0.2, 0.8, 2) + amplitude = np.random.uniform(0.05, 0.1) + sigma = 0.15 + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + candidate_centers = np.zeros((self.n, 2)) + candidate_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + candidate_centers[25] = void_center + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + initial_configs.append(candidate_centers) + + for centers in initial_configs: + # Refine each initial config with a short local search + refined_centers = self._force_directed_relaxation(centers, iters=100, step_size=0.002, repulsion_strength=0.01, + boundary_strength=0.05, repulsion_threshold=0.2, boundary_margin=0.05) + fitness = self._fitness(refined_centers) + self.population.append({'centers': refined_centers, 'fitness': fitness}) + + def _tournament_selection(self): + """Selects an individual using tournament selection.""" + best_ind = None + for _ in range(self.tournament_k): + ind = self.population[np.random.randint(0, self.pop_size)] + if best_ind is None or ind['fitness'] > best_ind['fitness']: + best_ind = ind + return best_ind + + def _kmeans_crossover(self, parent1, parent2): + """Creates a child by running K-Means on the combined parent centers.""" + combined_centers = np.vstack((parent1['centers'], parent2['centers'])) + + # Lightweight K-Means implementation + # 1. Initialize centroids by picking k points from the combined set + centroids = combined_centers[np.random.choice(2 * self.n, self.n, replace=False)] + + # 2. Iterate to refine centroids + for _ in range(10): # 10 iterations is sufficient for this purpose + # Assign points to closest centroid + diffs = combined_centers[:, np.newaxis, :] - centroids[np.newaxis, :, :] + dists_sq = np.sum(diffs**2, axis=2) + assignments = np.argmin(dists_sq, axis=1) + + # Update centroids to be the mean of their assigned points + new_centroids = np.array([combined_centers[assignments == k].mean(axis=0) for k in range(self.n)]) + # Handle empty clusters by not updating their centroid + for k in range(self.n): + if np.any(assignments == k): + centroids[k] = new_centroids[k] + + return np.clip(centroids, 0.0, 1.0) + + def _mutate(self, centers): + """Applies a random perturbation to a single circle.""" + mutated_centers = centers.copy() + + # Select a circle to mutate, prioritizing smaller ones + radii = compute_max_radii(mutated_centers) + inverse_radii = 1.0 / (radii + 1e-8) + probs = inverse_radii / np.sum(inverse_radii) + idx_to_mutate = np.random.choice(self.n, p=probs) + + # Apply mutation + displacement = np.random.uniform(-self.mutation_strength, self.mutation_strength, 2) + mutated_centers[idx_to_mutate] += displacement + mutated_centers[idx_to_mutate] = np.clip(mutated_centers[idx_to_mutate], 0.0, 1.0) + + return mutated_centers + + def pack(self): + """Main evolutionary loop.""" + self._initialize_population() + + for gen in range(self.generations): + parent1 = self._tournament_selection() + parent2 = self._tournament_selection() + + child_centers = self._kmeans_crossover(parent1, parent2) + + if np.random.rand() < self.mutation_rate: + child_centers = self._mutate(child_centers) + + # Local search (meme) on the new child + child_centers = self._force_directed_relaxation(child_centers, iters=80, step_size=0.001, repulsion_strength=0.005, + boundary_strength=0.02, repulsion_threshold=0.18, boundary_margin=0.03) + child_fitness = self._fitness(child_centers) + + # Find the worst individual to replace + worst_idx = min(range(self.pop_size), key=lambda i: self.population[i]['fitness']) + + # Elitist replacement: replace if better than the worst + if child_fitness > self.population[worst_idx]['fitness']: + self.population[worst_idx] = {'centers': child_centers, 'fitness': child_fitness} + + # Return the best individual from the final population + best_idx = max(range(self.pop_size), key=lambda i: self.population[i]['fitness']) + best_centers = self.population[best_idx]['centers'] + + # Final polish on the best result + final_centers = self._force_directed_relaxation(best_centers, iters=400, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.01) + + final_radii = compute_max_radii(final_centers) + return final_centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the MemeticPacker. + """ + n = 26 + packer = MemeticPacker(n=n, pop_size=40, generations=200, mutation_rate=0.5) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b2254691a90fe5f44b306c2eff0b329d091a3ab9 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..1c0aa12c119f72d90bf03097dc5925653668c4bc --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_152/main.py:77: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..eb5964ccfb1e68d7e33f22d902e99525d85de45c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_152/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_152/results +Run 1/1 completed in 65.36 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.181859785650679 + public: {'centers_str': ' centers[0] = (0.0882, 0.0876)\n centers[1] = (0.2987, 0.1264)\n centers[2] = (0.4879, 0.0696)\n centers[3] = (0.6631, 0.1102)\n centers[4] = (0.8860, 0.1089)\n centers[5] = (0.0636, 0.2368)\n centers[6] = (0.0873, 0.3858)\n centers[7] = (0.4502, 0.2938)\n centers[8] = (0.7138, 0.2604)\n centers[9] = (0.9077, 0.3091)\n centers[10] = (0.0657, 0.5372)\n centers[11] = (0.3722, 0.8125)\n centers[12] = (0.6183, 0.6089)\n centers[13] = (0.7291, 0.5255)\n centers[14] = (0.8989, 0.5023)\n centers[15] = (0.1024, 0.7012)\n centers[16] = (0.2815, 0.7273)\n centers[17] = (0.4680, 0.6856)\n centers[18] = (0.7079, 0.7043)\n centers[19] = (0.9087, 0.6943)\n centers[20] = (0.0982, 0.9018)\n centers[21] = (0.2949, 0.9026)\n centers[22] = (0.4952, 0.8983)\n centers[23] = (0.6901, 0.9066)\n centers[24] = (0.8921, 0.8924)\n centers[25] = (0.2782, 0.4862)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.181859785650679} + visualization_path: + execution_time_mean: 65.35848701093346 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..d6e3d73705e9f8cf98b35a003eb26ed1ea80dfdf --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.181859785650679, + "public": { + "centers_str": " centers[0] = (0.0882, 0.0876)\n centers[1] = (0.2987, 0.1264)\n centers[2] = (0.4879, 0.0696)\n centers[3] = (0.6631, 0.1102)\n centers[4] = (0.8860, 0.1089)\n centers[5] = (0.0636, 0.2368)\n centers[6] = (0.0873, 0.3858)\n centers[7] = (0.4502, 0.2938)\n centers[8] = (0.7138, 0.2604)\n centers[9] = (0.9077, 0.3091)\n centers[10] = (0.0657, 0.5372)\n centers[11] = (0.3722, 0.8125)\n centers[12] = (0.6183, 0.6089)\n centers[13] = (0.7291, 0.5255)\n centers[14] = (0.8989, 0.5023)\n centers[15] = (0.1024, 0.7012)\n centers[16] = (0.2815, 0.7273)\n centers[17] = (0.4680, 0.6856)\n centers[18] = (0.7079, 0.7043)\n centers[19] = (0.9087, 0.6943)\n centers[20] = (0.0982, 0.9018)\n centers[21] = (0.2949, 0.9026)\n centers[22] = (0.4952, 0.8983)\n centers[23] = (0.6901, 0.9066)\n centers[24] = (0.8921, 0.8924)\n centers[25] = (0.2782, 0.4862)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.181859785650679 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_152/results/packing_viz.png", + "execution_time_mean": 65.35848701093346, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d99c9f482036427353ba79b8cfd230e3f054a1c8 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..b5cadbf4dbee93ea1c5ca42191887e2e00ea4f09 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/edit.diff @@ -0,0 +1,326 @@ +--- a/original.py ++++ b/original.py +@@ -1,300 +1,320 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + + # compute_max_radii remains unchanged as it's a robust evaluation function. + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + + class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] # (N, N, 2) + dists = np.linalg.norm(diff, axis=2) # (N, N) + + # Mask out self-interaction by setting diagonal distances to a very large value + np.fill_diagonal(dists, np.inf) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors F_ij (force on i from j) + # F_ij direction is (centers[i] - centers[j]) / dists[i,j] + # Store unit vectors: normalized_diff[i,j] = (centers[i] - centers[j]) / dists[i,j] + normalized_diff = np.zeros_like(diff) + # Avoid division by zero where dists might be zero or inf (already handled diag to inf) + # The where clause ensures division only happens for valid non-zero distances. + # This covers the repulsion_mask values which are > 1e-9. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # Sum force_magnitudes[i,j] * normalized_diff[i,j] over j for each i + # This correctly sums F_ij (force exerted by j on i) for all j!=i + forces_repulsion = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + forces += forces_repulsion + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + ++ # Stagnation detection and escape parameters ++ stagnation_counter = 0 ++ stagnation_threshold = 1000 # Iterations without finding a new best to trigger a boost ++ perturb_boost = 1.0 ++ boost_factor = 3.0 # A strong, but not excessively disruptive, kick ++ boost_decay = 0.97 # Gradual decay of the boost ++ + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + ++ # Check for stagnation and apply a temporary perturbation boost ++ if stagnation_counter >= stagnation_threshold: ++ perturb_boost = boost_factor ++ stagnation_counter = 0 # Reset counter after triggering boost ++ + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. +- effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) ++ effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius +- effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) ++ effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + ++ # Decay the perturbation boost so its effect is temporary ++ if perturb_boost > 1.0: ++ perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() ++ stagnation_counter = 0 # Reset on new best ++ else: ++ stagnation_counter += 1 # Increment on accepted but not better ++ else: ++ stagnation_counter += 1 # Increment on reject + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( +- total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy ++ total_iterations=20000, # Increased iterations to support more thorough search with stagnation escape + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/main.py new file mode 100644 index 0000000000000000000000000000000000000000..c3080177233d6a809bf2ef2a8defc37b75073deb --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/main.py @@ -0,0 +1,320 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] # (N, N, 2) + dists = np.linalg.norm(diff, axis=2) # (N, N) + + # Mask out self-interaction by setting diagonal distances to a very large value + np.fill_diagonal(dists, np.inf) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors F_ij (force on i from j) + # F_ij direction is (centers[i] - centers[j]) / dists[i,j] + # Store unit vectors: normalized_diff[i,j] = (centers[i] - centers[j]) / dists[i,j] + normalized_diff = np.zeros_like(diff) + # Avoid division by zero where dists might be zero or inf (already handled diag to inf) + # The where clause ensures division only happens for valid non-zero distances. + # This covers the repulsion_mask values which are > 1e-9. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # Sum force_magnitudes[i,j] * normalized_diff[i,j] over j for each i + # This correctly sums F_ij (force exerted by j on i) for all j!=i + forces_repulsion = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + forces += forces_repulsion + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + # Stagnation detection and escape parameters + stagnation_counter = 0 + stagnation_threshold = 1000 # Iterations without finding a new best to trigger a boost + perturb_boost = 1.0 + boost_factor = 3.0 # A strong, but not excessively disruptive, kick + boost_decay = 0.97 # Gradual decay of the boost + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Check for stagnation and apply a temporary perturbation boost + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + stagnation_counter = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + stagnation_counter = 0 # Reset on new best + else: + stagnation_counter += 1 # Increment on accepted but not better + else: + stagnation_counter += 1 # Increment on reject + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( + total_iterations=20000, # Increased iterations to support more thorough search with stagnation escape + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/original.py new file mode 100644 index 0000000000000000000000000000000000000000..f781c5224681b92f8157711c916c44744e1a2414 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/original.py @@ -0,0 +1,300 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] # (N, N, 2) + dists = np.linalg.norm(diff, axis=2) # (N, N) + + # Mask out self-interaction by setting diagonal distances to a very large value + np.fill_diagonal(dists, np.inf) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors F_ij (force on i from j) + # F_ij direction is (centers[i] - centers[j]) / dists[i,j] + # Store unit vectors: normalized_diff[i,j] = (centers[i] - centers[j]) / dists[i,j] + normalized_diff = np.zeros_like(diff) + # Avoid division by zero where dists might be zero or inf (already handled diag to inf) + # The where clause ensures division only happens for valid non-zero distances. + # This covers the repulsion_mask values which are > 1e-9. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # Sum force_magnitudes[i,j] * normalized_diff[i,j] over j for each i + # This correctly sums F_ij (force exerted by j on i) for all j!=i + forces_repulsion = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + forces += forces_repulsion + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( + total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..170afd9be3bbe96c4a49028087b1eb203cdd0439 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_153/main.py:120: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..61ec1c0330d62b085334d523d5df587a0ef9387f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_153/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_153/results +Run 1/1 completed in 46.02 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.327101120203339 + public: {'centers_str': ' centers[0] = (0.0988, 0.0988)\n centers[1] = (0.2980, 0.1004)\n centers[2] = (0.6361, 0.0554)\n centers[3] = (0.7423, 0.0509)\n centers[4] = (0.8911, 0.1089)\n centers[5] = (0.0998, 0.2975)\n centers[6] = (0.5664, 0.6668)\n centers[7] = (0.4919, 0.0937)\n centers[8] = (0.6774, 0.2170)\n centers[9] = (0.8916, 0.3261)\n centers[10] = (0.1121, 0.5090)\n centers[11] = (0.2686, 0.5711)\n centers[12] = (0.3984, 0.3392)\n centers[13] = (0.6793, 0.4740)\n centers[14] = (0.9036, 0.5305)\n centers[15] = (0.1131, 0.7021)\n centers[16] = (0.3266, 0.7072)\n centers[17] = (0.4814, 0.7991)\n centers[18] = (0.7045, 0.7352)\n centers[19] = (0.9180, 0.7083)\n centers[20] = (0.0929, 0.9071)\n centers[21] = (0.2930, 0.8923)\n centers[22] = (0.5988, 0.9265)\n centers[23] = (0.7400, 0.9322)\n centers[24] = (0.9010, 0.8885)\n centers[25] = (0.4870, 0.5998)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.327101120203339} + visualization_path: + execution_time_mean: 46.024969063233584 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..1793872f21aea06140e5e48689388c63e8d02815 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.327101120203339, + "public": { + "centers_str": " centers[0] = (0.0988, 0.0988)\n centers[1] = (0.2980, 0.1004)\n centers[2] = (0.6361, 0.0554)\n centers[3] = (0.7423, 0.0509)\n centers[4] = (0.8911, 0.1089)\n centers[5] = (0.0998, 0.2975)\n centers[6] = (0.5664, 0.6668)\n centers[7] = (0.4919, 0.0937)\n centers[8] = (0.6774, 0.2170)\n centers[9] = (0.8916, 0.3261)\n centers[10] = (0.1121, 0.5090)\n centers[11] = (0.2686, 0.5711)\n centers[12] = (0.3984, 0.3392)\n centers[13] = (0.6793, 0.4740)\n centers[14] = (0.9036, 0.5305)\n centers[15] = (0.1131, 0.7021)\n centers[16] = (0.3266, 0.7072)\n centers[17] = (0.4814, 0.7991)\n centers[18] = (0.7045, 0.7352)\n centers[19] = (0.9180, 0.7083)\n centers[20] = (0.0929, 0.9071)\n centers[21] = (0.2930, 0.8923)\n centers[22] = (0.5988, 0.9265)\n centers[23] = (0.7400, 0.9322)\n centers[24] = (0.9010, 0.8885)\n centers[25] = (0.4870, 0.5998)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.327101120203339 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_153/results/packing_viz.png", + "execution_time_mean": 46.024969063233584, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..ccd4b6f66c443988d086fac21fc7fcfe186426d0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/rewrite.txt @@ -0,0 +1,238 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + Encapsulates the logic for packing circles using a hybrid strategy: + 1. Multi-start initialization to find a promising starting configuration. + 2. An advanced Simulated Annealing (SA) search with: + - Intelligent, context-aware circle selection for perturbation. + - Adaptive perturbation strength based on circle size. + - Stagnation detection and escape mechanism. + 3. Vectorized force-directed relaxation for initial settling and final polishing. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + + def _initialize_grid_with_void(self, void_center, amplitude, sigma): + """Initializes centers from a 5x5 grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + def _relax_phase(self, centers_to_relax, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation (jiggle) phase.""" + for _ in range(iters): + diff = centers_to_relax[:, np.newaxis, :] - centers_to_relax[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - centers_to_relax[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, centers_to_relax[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - centers_to_relax[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, centers_to_relax[:, 1] - (1 - boundary_margin)) + + centers_to_relax += step_size * forces + centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) + return centers_to_relax + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """Intelligently selects a circle to perturb based on radius, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(self.n) + for i in range(self.n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + # Count neighbors closer than 1.1 times the sum of radii + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 # Subtract self + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + + return np.random.choice(self.n, p=selection_probs) + + def _adaptive_perturbation(self, base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + # Factor is larger for smaller relative_radius + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + + def pack(self): + """Executes the full packing process.""" + + # --- 1. Multi-Start Initialization --- + best_initial_sum_radii = -1.0 + best_initial_centers = None + + # Try diverse void centers to find a promising start. + void_configs = [ + (np.random.uniform(0.3, 0.7, 2), 0.08), # Random + (np.array([0.4, 0.2]), 0.06), + (np.array([0.2, 0.4]), 0.05), + (np.array([0.6, 0.8]), 0.07), + (np.array([0.8, 0.6]), 0.065), + (np.array([0.5, 0.5]), 0.05), + ] + + for void_center, amplitude in void_configs: + candidate_centers = self._initialize_grid_with_void(void_center, amplitude, sigma=0.15) + + # Settle the initial configuration with a quick relaxation. + relaxed_centers = self._relax_phase( + candidate_centers.copy(), iters=200, step_size=0.002, + repulsion_strength=0.02, boundary_strength=0.07, + repulsion_threshold=0.2, boundary_margin=0.04 + ) + candidate_radii = compute_max_radii(relaxed_centers) + candidate_sum_radii = np.sum(candidate_radii) + + if candidate_sum_radii > best_initial_sum_radii: + best_initial_sum_radii = candidate_sum_radii + best_initial_centers = relaxed_centers.copy() + + # --- 2. Simulated Annealing Main Loop --- + current_centers = best_initial_centers + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_sum_radii = current_sum_radii + + # SA Parameters + total_iterations = 20000 + initial_temp = 0.0008 + final_temp = 1e-9 + initial_perturb_strength = 0.035 + final_perturb_strength = 0.0001 + + # Stagnation Escape Parameters + stagnation_counter = 0 + stagnation_threshold = 500 + perturb_boost = 1.0 + boost_factor = 2.5 + boost_decay = 0.98 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + + effective_perturb_strength = self._adaptive_perturbation(base_perturb_strength, circle_idx, current_radii) * perturb_boost + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the boost + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + # --- 3. Final Gentle Polish --- + final_centers = self._relax_phase( + best_centers, iters=300, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 + ) + final_radii = compute_max_radii(final_centers) + + return final_centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the advanced CirclePacker class. + """ + n = 26 + packer = CirclePacker(n) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..3e2fea1e43b8f2518e8cb58e6054b4a35cd411cd --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_153/search_replace.txt @@ -0,0 +1,242 @@ +Based on the visual analysis and my expertise in optimization algorithms, the current packing exhibits signs of being trapped in a local optimum. The large central circle disrupts the formation of a more globally efficient structure, and there are significant unused gaps. The Simulated Annealing (SA) search, while powerful, currently lacks a mechanism to escape such plateaus once the temperature and perturbation strength have decayed. + +My primary proposed change is to reintroduce a stagnation detection and escape mechanism that was present in a previous high-performing version. This mechanism will monitor the search progress. If no improvement to the best-found solution is made for a specified number of iterations, the algorithm will apply a temporary, significant boost to the perturbation strength. This "kick" can jolt the system out of a local minimum, allowing it to explore entirely new regions of the search space—for example, by dramatically resizing or moving the problematic large central circle. To support this more exploratory search, I will also increase the total number of SA iterations. + + +stagnation_escape_mechanism + + +This edit reintroduces a stagnation escape mechanism into the Simulated Annealing search. It works by tracking the number of iterations without an improvement to the globally best solution. If this count exceeds a threshold (`stagnation_threshold`), a temporary `perturb_boost` is applied to the perturbation strength, providing a "kick" to escape local optima. The boost then gradually decays. This helps the algorithm overcome situations like the one seen in the visualization, where a suboptimal arrangement is stable and hard to improve with small moves. I am also increasing the total SA iterations to give this more dynamic search process more time to converge. + + +<<<<<<< SEARCH + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience +======= + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + # Stagnation detection and escape parameters + stagnation_counter = 0 + stagnation_threshold = 1000 # Iterations without finding a new best to trigger a boost + perturb_boost = 1.0 + boost_factor = 3.0 # A strong, but not excessively disruptive, kick + boost_decay = 0.97 # Gradual decay of the boost + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Check for stagnation and apply a temporary perturbation boost + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + stagnation_counter = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + stagnation_counter = 0 # Reset on new best + else: + stagnation_counter += 1 # Increment on accepted but not better + else: + stagnation_counter += 1 # Increment on reject + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience +>>>>>>> REPLACE + + +<<<<<<< SEARCH + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( + total_iterations=15000, # Increased iterations for thorough SA search with new perturbation strategy + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) +======= + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( + total_iterations=20000, # Increased iterations to support more thorough search with stagnation escape + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6073246484eece0b9f85b1ccf481491a8f41ca67 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..584de65e995dad16d31bf412b8696fe7c82431ff --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/edit.diff @@ -0,0 +1,268 @@ +--- a/original.py ++++ b/original.py +@@ -1,250 +1,253 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles using a Hybrid Force-Directed Relaxation and Adaptive Simulated Annealing search""" + + import numpy as np + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i] = 0 + radii[j] = 0 + changes_made = True + + if not changes_made: + break + + return radii + + class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Use the same asymmetric starting point as successful previous models + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _apply_force_directed_relaxation(self, centers_to_relax, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies an aggressive force-directed relaxation algorithm to shake the initial grid. + """ + n_local = centers_to_relax.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers_to_relax) + + # Circle-circle repulsion + for i in range(n_local): + for j in range(i + 1, n_local): + vec = centers_to_relax[i] - centers_to_relax[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n_local): + x, y = centers_to_relax[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + centers_to_relax += step_size * forces + centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) + return centers_to_relax + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius and proximity to boundaries. + """ + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + # More sensitive to boundary proximity to encourage edge/corner optimization + boundary_proximity_weight = np.exp(-dist_to_nearest_boundary / 0.05) + + combined_weights = inverse_radii * (1 + boundary_proximity_weight) + selection_probs = combined_weights / np.sum(combined_weights) + + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength. Smaller circles get a bigger push. + """ + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r +- # Increase multiplier to 2.5 for more aggressive movement of small circles +- perturb_factor = 1.0 + (1.0 - relative_radius) * 2.5 ++ # Increase multiplier to 3.0 for even more aggressive movement of small circles. ++ # This directly addresses the visually-identified problem of tiny, trapped circles. ++ perturb_factor = 1.0 + (1.0 - relative_radius) * 3.0 + + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing. + """ + self._initialize_centers() + +- # Pre-optimization with an aggressive Force-Directed Relaxation stage to break the grid ++ # Pre-optimization with a milder Force-Directed Relaxation to settle the initial state. ++ # An overly aggressive FDR can lead to a chaotic state which is a poor start for SA. ++ # These parameters are borrowed from a higher-scoring ancestor. + self.centers = self._apply_force_directed_relaxation( + self.centers.copy(), +- iterations=800, +- step_size=0.002, +- repulsion_strength=0.015, +- repulsion_threshold=0.22, +- boundary_strength=0.08, +- boundary_margin=0.04 ++ iterations=500, ++ step_size=0.001, ++ repulsion_strength=0.01, ++ repulsion_threshold=0.18, ++ boundary_strength=0.05, ++ boundary_margin=0.03 + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + +- total_iterations = 18000 ++ total_iterations = 20000 # More time for the search to converge + initial_global_perturb_strength_base = 0.05 # Higher initial perturbation + final_global_perturb_strength = 0.0002 + + T_initial = 0.25 # Much higher initial temperature for extensive exploration + T_final = 1e-7 + + no_improvement_count = 0 +- max_no_improvement_steps = 600 ++ max_no_improvement_steps = 700 # Allow more steps before triggering escape + current_initial_global_perturb_strength = initial_global_perturb_strength_base + + for iteration in range(total_iterations): + # Schedules for perturbation and temperature + global_perturb_strength = current_initial_global_perturb_strength * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + effective_perturb_strength = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # SA acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + delta = candidate_sum_radii - current_sum_radii + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and check for stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + # Stagnation escape: temporarily boost perturbation + if no_improvement_count > max_no_improvement_steps: +- current_initial_global_perturb_strength *= 1.25 # Stronger boost ++ current_initial_global_perturb_strength *= 1.3 # Use a stronger boost to escape + no_improvement_count = 0 # Reset counter + + return best_centers, best_radii + + def construct_packing(): + """ + Main function to construct the circle packing. + """ + packer = CirclePacker(n=26) + return packer.pack() + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/main.py new file mode 100644 index 0000000000000000000000000000000000000000..32d6a726e3934ead609892f31293891068eed0ed --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/main.py @@ -0,0 +1,253 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using a Hybrid Force-Directed Relaxation and Adaptive Simulated Annealing search""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i] = 0 + radii[j] = 0 + changes_made = True + + if not changes_made: + break + + return radii + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Use the same asymmetric starting point as successful previous models + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _apply_force_directed_relaxation(self, centers_to_relax, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies an aggressive force-directed relaxation algorithm to shake the initial grid. + """ + n_local = centers_to_relax.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers_to_relax) + + # Circle-circle repulsion + for i in range(n_local): + for j in range(i + 1, n_local): + vec = centers_to_relax[i] - centers_to_relax[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n_local): + x, y = centers_to_relax[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + centers_to_relax += step_size * forces + centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) + return centers_to_relax + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius and proximity to boundaries. + """ + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + # More sensitive to boundary proximity to encourage edge/corner optimization + boundary_proximity_weight = np.exp(-dist_to_nearest_boundary / 0.05) + + combined_weights = inverse_radii * (1 + boundary_proximity_weight) + selection_probs = combined_weights / np.sum(combined_weights) + + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength. Smaller circles get a bigger push. + """ + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + # Increase multiplier to 3.0 for even more aggressive movement of small circles. + # This directly addresses the visually-identified problem of tiny, trapped circles. + perturb_factor = 1.0 + (1.0 - relative_radius) * 3.0 + + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing. + """ + self._initialize_centers() + + # Pre-optimization with a milder Force-Directed Relaxation to settle the initial state. + # An overly aggressive FDR can lead to a chaotic state which is a poor start for SA. + # These parameters are borrowed from a higher-scoring ancestor. + self.centers = self._apply_force_directed_relaxation( + self.centers.copy(), + iterations=500, + step_size=0.001, + repulsion_strength=0.01, + repulsion_threshold=0.18, + boundary_strength=0.05, + boundary_margin=0.03 + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + total_iterations = 20000 # More time for the search to converge + initial_global_perturb_strength_base = 0.05 # Higher initial perturbation + final_global_perturb_strength = 0.0002 + + T_initial = 0.25 # Much higher initial temperature for extensive exploration + T_final = 1e-7 + + no_improvement_count = 0 + max_no_improvement_steps = 700 # Allow more steps before triggering escape + current_initial_global_perturb_strength = initial_global_perturb_strength_base + + for iteration in range(total_iterations): + # Schedules for perturbation and temperature + global_perturb_strength = current_initial_global_perturb_strength * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + effective_perturb_strength = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # SA acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + delta = candidate_sum_radii - current_sum_radii + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and check for stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + # Stagnation escape: temporarily boost perturbation + if no_improvement_count > max_no_improvement_steps: + current_initial_global_perturb_strength *= 1.3 # Use a stronger boost to escape + no_improvement_count = 0 # Reset counter + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + """ + packer = CirclePacker(n=26) + return packer.pack() +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/original.py new file mode 100644 index 0000000000000000000000000000000000000000..863e6498d8d7d62d39bb471718a8427bfd4be345 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/original.py @@ -0,0 +1,250 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using a Hybrid Force-Directed Relaxation and Adaptive Simulated Annealing search""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i] = 0 + radii[j] = 0 + changes_made = True + + if not changes_made: + break + + return radii + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Use the same asymmetric starting point as successful previous models + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _apply_force_directed_relaxation(self, centers_to_relax, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies an aggressive force-directed relaxation algorithm to shake the initial grid. + """ + n_local = centers_to_relax.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers_to_relax) + + # Circle-circle repulsion + for i in range(n_local): + for j in range(i + 1, n_local): + vec = centers_to_relax[i] - centers_to_relax[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n_local): + x, y = centers_to_relax[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + centers_to_relax += step_size * forces + centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) + return centers_to_relax + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius and proximity to boundaries. + """ + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + # More sensitive to boundary proximity to encourage edge/corner optimization + boundary_proximity_weight = np.exp(-dist_to_nearest_boundary / 0.05) + + combined_weights = inverse_radii * (1 + boundary_proximity_weight) + selection_probs = combined_weights / np.sum(combined_weights) + + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength. Smaller circles get a bigger push. + """ + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + # Increase multiplier to 2.5 for more aggressive movement of small circles + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.5 + + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing. + """ + self._initialize_centers() + + # Pre-optimization with an aggressive Force-Directed Relaxation stage to break the grid + self.centers = self._apply_force_directed_relaxation( + self.centers.copy(), + iterations=800, + step_size=0.002, + repulsion_strength=0.015, + repulsion_threshold=0.22, + boundary_strength=0.08, + boundary_margin=0.04 + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + total_iterations = 18000 + initial_global_perturb_strength_base = 0.05 # Higher initial perturbation + final_global_perturb_strength = 0.0002 + + T_initial = 0.25 # Much higher initial temperature for extensive exploration + T_final = 1e-7 + + no_improvement_count = 0 + max_no_improvement_steps = 600 + current_initial_global_perturb_strength = initial_global_perturb_strength_base + + for iteration in range(total_iterations): + # Schedules for perturbation and temperature + global_perturb_strength = current_initial_global_perturb_strength * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + effective_perturb_strength = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # SA acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + delta = candidate_sum_radii - current_sum_radii + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and check for stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 + else: + no_improvement_count += 1 + # Stagnation escape: temporarily boost perturbation + if no_improvement_count > max_no_improvement_steps: + current_initial_global_perturb_strength *= 1.25 # Stronger boost + no_improvement_count = 0 # Reset counter + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + """ + packer = CirclePacker(n=26) + return packer.pack() +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..13a78a08860468233181f6eb171b435721ce031b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_156/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_156/results +Run 1/1 completed in 42.90 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.0540660653285165 + public: {'centers_str': ' centers[0] = (0.2641, 0.1445)\n centers[1] = (0.4367, 0.8112)\n centers[2] = (0.9129, 0.9034)\n centers[3] = (0.5870, 0.2964)\n centers[4] = (0.1443, 0.8863)\n centers[5] = (0.9166, 0.3606)\n centers[6] = (0.1242, 0.3199)\n centers[7] = (0.4576, 0.5922)\n centers[8] = (0.0871, 0.0768)\n centers[9] = (0.8832, 0.5283)\n centers[10] = (0.4354, 0.9399)\n centers[11] = (0.6651, 0.8423)\n centers[12] = (0.2045, 0.6962)\n centers[13] = (0.6752, 0.4812)\n centers[14] = (0.7800, 0.6039)\n centers[15] = (0.0856, 0.4945)\n centers[16] = (0.9135, 0.6460)\n centers[17] = (0.3518, 0.3669)\n centers[18] = (0.0655, 0.2057)\n centers[19] = (0.4301, 0.1312)\n centers[20] = (0.2049, 0.5603)\n centers[21] = (0.9640, 0.7773)\n centers[22] = (0.3013, 0.9152)\n centers[23] = (0.8792, 0.1714)\n centers[24] = (0.6604, 0.1091)\n centers[25] = (0.0714, 0.6790)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.0540660653285165} + visualization_path: + execution_time_mean: 42.902525070123374 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..821d1c48d0afe358cb8445115fa87462186a6948 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.0540660653285165, + "public": { + "centers_str": " centers[0] = (0.2641, 0.1445)\n centers[1] = (0.4367, 0.8112)\n centers[2] = (0.9129, 0.9034)\n centers[3] = (0.5870, 0.2964)\n centers[4] = (0.1443, 0.8863)\n centers[5] = (0.9166, 0.3606)\n centers[6] = (0.1242, 0.3199)\n centers[7] = (0.4576, 0.5922)\n centers[8] = (0.0871, 0.0768)\n centers[9] = (0.8832, 0.5283)\n centers[10] = (0.4354, 0.9399)\n centers[11] = (0.6651, 0.8423)\n centers[12] = (0.2045, 0.6962)\n centers[13] = (0.6752, 0.4812)\n centers[14] = (0.7800, 0.6039)\n centers[15] = (0.0856, 0.4945)\n centers[16] = (0.9135, 0.6460)\n centers[17] = (0.3518, 0.3669)\n centers[18] = (0.0655, 0.2057)\n centers[19] = (0.4301, 0.1312)\n centers[20] = (0.2049, 0.5603)\n centers[21] = (0.9640, 0.7773)\n centers[22] = (0.3013, 0.9152)\n centers[23] = (0.8792, 0.1714)\n centers[24] = (0.6604, 0.1091)\n centers[25] = (0.0714, 0.6790)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.0540660653285165 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_156/results/packing_viz.png", + "execution_time_mean": 42.902525070123374, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..054fd2cd3c297acfd2179df5064847824913ebbe --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_156/search_replace.txt @@ -0,0 +1,86 @@ + +balanced_fdr_and_boosted_sa + + +The current configuration appears to suffer from a chaotic state induced by an overly aggressive Force-Directed Relaxation (FDR), which the Simulated Annealing (SA) cannot untangle. This leads to suboptimal packings with trapped small circles and large gaps, as seen in the visualization. + +This edit implements a two-pronged strategy to address this: + +1. **Balanced Pre-optimization:** The FDR parameters are reverted to a milder configuration successfully used by a high-scoring ancestor. This creates a more structured and promising initial state for the SA, preventing it from starting in a deep, chaotic local minimum. + +2. **Boosted SA Search:** The SA is enhanced to better explore the solution space and escape local minima. + * The adaptive perturbation strength for small circles is significantly increased (multiplier from 2.5 to 3.0) to directly address the observed issue of trapped small circles. + * The total iterations are increased to 20,000 to give this more powerful search more time to work. + * The stagnation escape mechanism is made more patient (`max_no_improvement_steps` to 700) and more powerful (boost factor to 1.3) to better handle plateaus in the search landscape. + +This combined approach of a better starting point and a more powerful search algorithm should allow the system to discover denser, more ordered packing configurations. + + +<<<<<<< SEARCH + # Increase multiplier to 2.5 for more aggressive movement of small circles + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.5 +======= + # Increase multiplier to 3.0 for even more aggressive movement of small circles. + # This directly addresses the visually-identified problem of tiny, trapped circles. + perturb_factor = 1.0 + (1.0 - relative_radius) * 3.0 +>>>>>>> REPLACE +<<<<<<< SEARCH + # Pre-optimization with an aggressive Force-Directed Relaxation stage to break the grid + self.centers = self._apply_force_directed_relaxation( + self.centers.copy(), + iterations=800, + step_size=0.002, + repulsion_strength=0.015, + repulsion_threshold=0.22, + boundary_strength=0.08, + boundary_margin=0.04 + ) +======= + # Pre-optimization with a milder Force-Directed Relaxation to settle the initial state. + # An overly aggressive FDR can lead to a chaotic state which is a poor start for SA. + # These parameters are borrowed from a higher-scoring ancestor. + self.centers = self._apply_force_directed_relaxation( + self.centers.copy(), + iterations=500, + step_size=0.001, + repulsion_strength=0.01, + repulsion_threshold=0.18, + boundary_strength=0.05, + boundary_margin=0.03 + ) +>>>>>>> REPLACE +<<<<<<< SEARCH + total_iterations = 18000 + initial_global_perturb_strength_base = 0.05 # Higher initial perturbation + final_global_perturb_strength = 0.0002 + + T_initial = 0.25 # Much higher initial temperature for extensive exploration + T_final = 1e-7 + + no_improvement_count = 0 + max_no_improvement_steps = 600 + current_initial_global_perturb_strength = initial_global_perturb_strength_base +======= + total_iterations = 20000 # More time for the search to converge + initial_global_perturb_strength_base = 0.05 # Higher initial perturbation + final_global_perturb_strength = 0.0002 + + T_initial = 0.25 # Much higher initial temperature for extensive exploration + T_final = 1e-7 + + no_improvement_count = 0 + max_no_improvement_steps = 700 # Allow more steps before triggering escape + current_initial_global_perturb_strength = initial_global_perturb_strength_base +>>>>>>> REPLACE +<<<<<<< SEARCH + # Stagnation escape: temporarily boost perturbation + if no_improvement_count > max_no_improvement_steps: + current_initial_global_perturb_strength *= 1.25 # Stronger boost + no_improvement_count = 0 # Reset counter +======= + # Stagnation escape: temporarily boost perturbation + if no_improvement_count > max_no_improvement_steps: + current_initial_global_perturb_strength *= 1.3 # Use a stronger boost to escape + no_improvement_count = 0 # Reset counter +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e22596ac9e366251ab68420582356f0d2c956833 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..dd775798b6dada59ed23e167ec602441a58952d1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_157/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_157/results +Run 1/1 completed in 44.71 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.1805061037386877 + public: {'centers_str': ' centers[0] = (0.2615, 0.8842)\n centers[1] = (0.0926, 0.5798)\n centers[2] = (0.6892, 0.3428)\n centers[3] = (0.0663, 0.4214)\n centers[4] = (0.4500, 0.9355)\n centers[5] = (0.3416, 0.3076)\n centers[6] = (0.7110, 0.2569)\n centers[7] = (0.5565, 0.1234)\n centers[8] = (0.0818, 0.0683)\n centers[9] = (0.8629, 0.1440)\n centers[10] = (0.5446, 0.5183)\n centers[11] = (0.3824, 0.7341)\n centers[12] = (0.9217, 0.7440)\n centers[13] = (0.3334, 0.9481)\n centers[14] = (0.9257, 0.5487)\n centers[15] = (0.1037, 0.2563)\n centers[16] = (0.2248, 0.5120)\n centers[17] = (0.2645, 0.0959)\n centers[18] = (0.8231, 0.6593)\n centers[19] = (0.8121, 0.3945)\n centers[20] = (0.1461, 0.7415)\n centers[21] = (0.1286, 0.9297)\n centers[22] = (0.8041, 0.8740)\n centers[23] = (0.5952, 0.9107)\n centers[24] = (0.6153, 0.7039)\n centers[25] = (0.5881, 0.3511)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.1805061037386877} + visualization_path: + execution_time_mean: 44.71031014295295 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..a6eb7f3de0ea9071853e58bfddb6b14ed8998683 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.1805061037386877, + "public": { + "centers_str": " centers[0] = (0.2615, 0.8842)\n centers[1] = (0.0926, 0.5798)\n centers[2] = (0.6892, 0.3428)\n centers[3] = (0.0663, 0.4214)\n centers[4] = (0.4500, 0.9355)\n centers[5] = (0.3416, 0.3076)\n centers[6] = (0.7110, 0.2569)\n centers[7] = (0.5565, 0.1234)\n centers[8] = (0.0818, 0.0683)\n centers[9] = (0.8629, 0.1440)\n centers[10] = (0.5446, 0.5183)\n centers[11] = (0.3824, 0.7341)\n centers[12] = (0.9217, 0.7440)\n centers[13] = (0.3334, 0.9481)\n centers[14] = (0.9257, 0.5487)\n centers[15] = (0.1037, 0.2563)\n centers[16] = (0.2248, 0.5120)\n centers[17] = (0.2645, 0.0959)\n centers[18] = (0.8231, 0.6593)\n centers[19] = (0.8121, 0.3945)\n centers[20] = (0.1461, 0.7415)\n centers[21] = (0.1286, 0.9297)\n centers[22] = (0.8041, 0.8740)\n centers[23] = (0.5952, 0.9107)\n centers[24] = (0.6153, 0.7039)\n centers[25] = (0.5881, 0.3511)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.1805061037386877 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_157/results/packing_viz.png", + "execution_time_mean": 44.71031014295295, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37c4f520e63968531e25ad8799918180ce2b7604 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..58ba44de3af5de3de4aa30eb810a8e45776c707c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_158/main.py:105: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..037dab9942d703a1ab1303c025784bd007b4caf9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_158/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_158/results +Run 1/1 completed in 44.44 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.242241480769099 + public: {'centers_str': ' centers[0] = (0.0886, 0.0886)\n centers[1] = (0.2394, 0.0642)\n centers[2] = (0.5273, 0.1130)\n centers[3] = (0.7165, 0.0792)\n centers[4] = (0.8971, 0.1028)\n centers[5] = (0.1043, 0.2808)\n centers[6] = (0.5951, 0.6454)\n centers[7] = (0.5672, 0.3190)\n centers[8] = (0.7178, 0.2858)\n centers[9] = (0.9051, 0.3004)\n centers[10] = (0.0892, 0.4736)\n centers[11] = (0.2981, 0.5944)\n centers[12] = (0.4933, 0.4620)\n centers[13] = (0.6948, 0.4852)\n centers[14] = (0.9041, 0.4912)\n centers[15] = (0.0871, 0.6686)\n centers[16] = (0.2510, 0.7255)\n centers[17] = (0.4586, 0.6757)\n centers[18] = (0.6854, 0.6995)\n centers[19] = (0.8932, 0.6937)\n centers[20] = (0.1022, 0.8946)\n centers[21] = (0.3019, 0.9024)\n centers[22] = (0.4999, 0.8995)\n centers[23] = (0.7005, 0.9000)\n centers[24] = (0.9002, 0.9002)\n centers[25] = (0.3662, 0.2356)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.242241480769099} + visualization_path: + execution_time_mean: 44.438045625109226 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..f03664b3b97bc02f18253b31329af9ee52b5b418 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.242241480769099, + "public": { + "centers_str": " centers[0] = (0.0886, 0.0886)\n centers[1] = (0.2394, 0.0642)\n centers[2] = (0.5273, 0.1130)\n centers[3] = (0.7165, 0.0792)\n centers[4] = (0.8971, 0.1028)\n centers[5] = (0.1043, 0.2808)\n centers[6] = (0.5951, 0.6454)\n centers[7] = (0.5672, 0.3190)\n centers[8] = (0.7178, 0.2858)\n centers[9] = (0.9051, 0.3004)\n centers[10] = (0.0892, 0.4736)\n centers[11] = (0.2981, 0.5944)\n centers[12] = (0.4933, 0.4620)\n centers[13] = (0.6948, 0.4852)\n centers[14] = (0.9041, 0.4912)\n centers[15] = (0.0871, 0.6686)\n centers[16] = (0.2510, 0.7255)\n centers[17] = (0.4586, 0.6757)\n centers[18] = (0.6854, 0.6995)\n centers[19] = (0.8932, 0.6937)\n centers[20] = (0.1022, 0.8946)\n centers[21] = (0.3019, 0.9024)\n centers[22] = (0.4999, 0.8995)\n centers[23] = (0.7005, 0.9000)\n centers[24] = (0.9002, 0.9002)\n centers[25] = (0.3662, 0.2356)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.242241480769099 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_158/results/packing_viz.png", + "execution_time_mean": 44.438045625109226, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..73f979022bfc964dfc4caf19c8ece768b18378d2 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..3f660451e36997f62cc451f4f642e40fb0dd8ac6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/edit.diff @@ -0,0 +1,195 @@ +--- a/original.py ++++ b/original.py +@@ -1,184 +1,187 @@ + # EVOLVE-BLOCK-START + """ + Constructor-based circle packing for n=26 circles using a hybrid approach: + a force-directed pre-relaxation followed by an advanced Simulated Annealing search. + """ + + import numpy as np + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + """ + n = centers.shape[0] + # Initialize radii based on distance to boundaries (vectorized) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps until convergence + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + + def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles. This method combines + a proven asymmetric initialization, a mild force-directed pre-relaxation, + and a sophisticated Simulated Annealing local search with adaptive heuristics. + """ + n = 26 + + # 1. Initialization: Asymmetric Gaussian-deformed grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + void_center = np.array([0.4, 0.2]) + amplitude, sigma = 0.06, 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 2. Pre-optimization: A mild force-directed relaxation to settle the initial state. + centers = apply_force_directed_relaxation( + centers, iterations=500, step_size=0.001, repulsion_strength=0.01, + repulsion_threshold=0.18, boundary_strength=0.05, boundary_margin=0.03 + ) + + # 3. Main Optimization: Advanced Simulated Annealing with Stagnation Escape. + radii = compute_max_radii(centers) + + best_centers = centers.copy() + best_radii = radii.copy() + best_sum_radii = np.sum(radii) + + current_centers = centers.copy() + current_radii = radii.copy() + current_sum_radii = best_sum_radii + + # Tuned SA parameters based on high-performing ancestors for better exploration + total_iterations = 15000 + initial_g_perturb_base = 0.04 + final_g_perturb = 0.0003 + T_initial, T_final = 0.2, 1e-7 + + # Stagnation escape mechanism to kick search out of local optima + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_g_perturb = initial_g_perturb_base + + for it in range(total_iterations): + # Annealing schedules with dynamic perturbation + g_perturb = current_initial_g_perturb + (final_g_perturb - current_initial_g_perturb) * (it / total_iterations) + temp = T_initial * (T_final / T_initial)**(it / total_iterations) + + candidate_centers = current_centers.copy() + +- # Adaptive Selection: Prioritize small circles and those near boundaries +- inverse_radii = 1 / (current_radii + 1e-8) ++ # Adaptive Selection: Prioritize small circles and those near boundaries. ++ # The weighting exponent is reduced from 1.0 to 0.75 to give larger circles ++ # a slightly higher probability of being selected and moved, helping to resolve ++ # large-scale structural inefficiencies. ++ size_weight = (1 / (current_radii + 1e-8))**0.75 + dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.1) +- weights = inverse_radii * (1 + boundary_weight) ++ weights = size_weight * (1 + boundary_weight) + probs = weights / np.sum(weights) + circle_idx = np.random.choice(n, p=probs) + + # Adaptive Perturbation: Give larger kicks to smaller circles + max_r = np.max(current_radii) + 1e-8 + relative_r = current_radii[circle_idx] / max_r +- # Increased multiplier for more aggressive small circle movement +- perturb_factor = 1.0 + (1.0 - relative_r) * 2.0 ++ # Increased multiplier for even more aggressive small circle movement, helping them escape tight spots. ++ perturb_factor = 1.0 + (1.0 - relative_r) * 2.5 + eff_perturb = g_perturb * perturb_factor + + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluation and Acceptance + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + accepted = False + delta = candidate_sum_radii - current_sum_radii + if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best + elif not accepted: + no_improvement_count += 1 + # If stagnated, boost perturbation to escape local optimum + if no_improvement_count > max_no_improvement_steps: + current_initial_g_perturb *= 1.2 + no_improvement_count = 0 + + return best_centers, best_radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/main.py new file mode 100644 index 0000000000000000000000000000000000000000..f875c965615ddd96161972bd0c3516b1f4620de9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/main.py @@ -0,0 +1,187 @@ +# EVOLVE-BLOCK-START +""" +Constructor-based circle packing for n=26 circles using a hybrid approach: +a force-directed pre-relaxation followed by an advanced Simulated Annealing search. +""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + """ + n = centers.shape[0] + # Initialize radii based on distance to boundaries (vectorized) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps until convergence + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles. This method combines + a proven asymmetric initialization, a mild force-directed pre-relaxation, + and a sophisticated Simulated Annealing local search with adaptive heuristics. + """ + n = 26 + + # 1. Initialization: Asymmetric Gaussian-deformed grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + void_center = np.array([0.4, 0.2]) + amplitude, sigma = 0.06, 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 2. Pre-optimization: A mild force-directed relaxation to settle the initial state. + centers = apply_force_directed_relaxation( + centers, iterations=500, step_size=0.001, repulsion_strength=0.01, + repulsion_threshold=0.18, boundary_strength=0.05, boundary_margin=0.03 + ) + + # 3. Main Optimization: Advanced Simulated Annealing with Stagnation Escape. + radii = compute_max_radii(centers) + + best_centers = centers.copy() + best_radii = radii.copy() + best_sum_radii = np.sum(radii) + + current_centers = centers.copy() + current_radii = radii.copy() + current_sum_radii = best_sum_radii + + # Tuned SA parameters based on high-performing ancestors for better exploration + total_iterations = 15000 + initial_g_perturb_base = 0.04 + final_g_perturb = 0.0003 + T_initial, T_final = 0.2, 1e-7 + + # Stagnation escape mechanism to kick search out of local optima + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_g_perturb = initial_g_perturb_base + + for it in range(total_iterations): + # Annealing schedules with dynamic perturbation + g_perturb = current_initial_g_perturb + (final_g_perturb - current_initial_g_perturb) * (it / total_iterations) + temp = T_initial * (T_final / T_initial)**(it / total_iterations) + + candidate_centers = current_centers.copy() + + # Adaptive Selection: Prioritize small circles and those near boundaries. + # The weighting exponent is reduced from 1.0 to 0.75 to give larger circles + # a slightly higher probability of being selected and moved, helping to resolve + # large-scale structural inefficiencies. + size_weight = (1 / (current_radii + 1e-8))**0.75 + dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.1) + weights = size_weight * (1 + boundary_weight) + probs = weights / np.sum(weights) + circle_idx = np.random.choice(n, p=probs) + + # Adaptive Perturbation: Give larger kicks to smaller circles + max_r = np.max(current_radii) + 1e-8 + relative_r = current_radii[circle_idx] / max_r + # Increased multiplier for even more aggressive small circle movement, helping them escape tight spots. + perturb_factor = 1.0 + (1.0 - relative_r) * 2.5 + eff_perturb = g_perturb * perturb_factor + + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluation and Acceptance + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + accepted = False + delta = candidate_sum_radii - current_sum_radii + if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best + elif not accepted: + no_improvement_count += 1 + # If stagnated, boost perturbation to escape local optimum + if no_improvement_count > max_no_improvement_steps: + current_initial_g_perturb *= 1.2 + no_improvement_count = 0 + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/original.py new file mode 100644 index 0000000000000000000000000000000000000000..f1c7e54d0435ebc31fdc5394d04006f30db3885a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/original.py @@ -0,0 +1,184 @@ +# EVOLVE-BLOCK-START +""" +Constructor-based circle packing for n=26 circles using a hybrid approach: +a force-directed pre-relaxation followed by an advanced Simulated Annealing search. +""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + """ + n = centers.shape[0] + # Initialize radii based on distance to boundaries (vectorized) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps until convergence + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles. This method combines + a proven asymmetric initialization, a mild force-directed pre-relaxation, + and a sophisticated Simulated Annealing local search with adaptive heuristics. + """ + n = 26 + + # 1. Initialization: Asymmetric Gaussian-deformed grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + void_center = np.array([0.4, 0.2]) + amplitude, sigma = 0.06, 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 2. Pre-optimization: A mild force-directed relaxation to settle the initial state. + centers = apply_force_directed_relaxation( + centers, iterations=500, step_size=0.001, repulsion_strength=0.01, + repulsion_threshold=0.18, boundary_strength=0.05, boundary_margin=0.03 + ) + + # 3. Main Optimization: Advanced Simulated Annealing with Stagnation Escape. + radii = compute_max_radii(centers) + + best_centers = centers.copy() + best_radii = radii.copy() + best_sum_radii = np.sum(radii) + + current_centers = centers.copy() + current_radii = radii.copy() + current_sum_radii = best_sum_radii + + # Tuned SA parameters based on high-performing ancestors for better exploration + total_iterations = 15000 + initial_g_perturb_base = 0.04 + final_g_perturb = 0.0003 + T_initial, T_final = 0.2, 1e-7 + + # Stagnation escape mechanism to kick search out of local optima + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_g_perturb = initial_g_perturb_base + + for it in range(total_iterations): + # Annealing schedules with dynamic perturbation + g_perturb = current_initial_g_perturb + (final_g_perturb - current_initial_g_perturb) * (it / total_iterations) + temp = T_initial * (T_final / T_initial)**(it / total_iterations) + + candidate_centers = current_centers.copy() + + # Adaptive Selection: Prioritize small circles and those near boundaries + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.1) + weights = inverse_radii * (1 + boundary_weight) + probs = weights / np.sum(weights) + circle_idx = np.random.choice(n, p=probs) + + # Adaptive Perturbation: Give larger kicks to smaller circles + max_r = np.max(current_radii) + 1e-8 + relative_r = current_radii[circle_idx] / max_r + # Increased multiplier for more aggressive small circle movement + perturb_factor = 1.0 + (1.0 - relative_r) * 2.0 + eff_perturb = g_perturb * perturb_factor + + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluation and Acceptance + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + accepted = False + delta = candidate_sum_radii - current_sum_radii + if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best + elif not accepted: + no_improvement_count += 1 + # If stagnated, boost perturbation to escape local optimum + if no_improvement_count > max_no_improvement_steps: + current_initial_g_perturb *= 1.2 + no_improvement_count = 0 + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..933305804b5eb5a9a77341e4c7223fd36749ec22 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_159/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_159/results +Run 1/1 completed in 32.10 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.268799669694198 + public: {'centers_str': ' centers[0] = (0.8358, 0.0354)\n centers[1] = (0.6363, 0.4745)\n centers[2] = (0.8230, 0.2917)\n centers[3] = (0.5116, 0.1343)\n centers[4] = (0.3131, 0.9411)\n centers[5] = (0.0402, 0.4154)\n centers[6] = (0.5658, 0.7380)\n centers[7] = (0.2561, 0.0865)\n centers[8] = (0.9096, 0.1371)\n centers[9] = (0.9058, 0.5029)\n centers[10] = (0.1419, 0.8348)\n centers[11] = (0.1384, 0.5278)\n centers[12] = (0.3598, 0.4840)\n centers[13] = (0.3795, 0.2386)\n centers[14] = (0.6943, 0.1222)\n centers[15] = (0.4536, 0.9236)\n centers[16] = (0.0593, 0.6510)\n centers[17] = (0.8935, 0.8938)\n centers[18] = (0.7849, 0.6862)\n centers[19] = (0.9451, 0.3621)\n centers[20] = (0.1380, 0.2741)\n centers[21] = (0.7372, 0.4823)\n centers[22] = (0.3846, 0.7402)\n centers[23] = (0.5855, 0.3459)\n centers[24] = (0.6551, 0.8886)\n centers[25] = (0.5805, 0.5769)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.268799669694198} + visualization_path: + execution_time_mean: 32.09720972785726 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..c26cc2951408dd0695b97b86cf4aee69738c60e0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.268799669694198, + "public": { + "centers_str": " centers[0] = (0.8358, 0.0354)\n centers[1] = (0.6363, 0.4745)\n centers[2] = (0.8230, 0.2917)\n centers[3] = (0.5116, 0.1343)\n centers[4] = (0.3131, 0.9411)\n centers[5] = (0.0402, 0.4154)\n centers[6] = (0.5658, 0.7380)\n centers[7] = (0.2561, 0.0865)\n centers[8] = (0.9096, 0.1371)\n centers[9] = (0.9058, 0.5029)\n centers[10] = (0.1419, 0.8348)\n centers[11] = (0.1384, 0.5278)\n centers[12] = (0.3598, 0.4840)\n centers[13] = (0.3795, 0.2386)\n centers[14] = (0.6943, 0.1222)\n centers[15] = (0.4536, 0.9236)\n centers[16] = (0.0593, 0.6510)\n centers[17] = (0.8935, 0.8938)\n centers[18] = (0.7849, 0.6862)\n centers[19] = (0.9451, 0.3621)\n centers[20] = (0.1380, 0.2741)\n centers[21] = (0.7372, 0.4823)\n centers[22] = (0.3846, 0.7402)\n centers[23] = (0.5855, 0.3459)\n centers[24] = (0.6551, 0.8886)\n centers[25] = (0.5805, 0.5769)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.268799669694198 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_159/results/packing_viz.png", + "execution_time_mean": 32.09720972785726, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ce280aeff9423f4edc1eb33f8d88656506183c1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_159/search_replace.txt @@ -0,0 +1,45 @@ +Based on my analysis of the circle packing visualization, the current arrangement shows good density but has clear areas for improvement. Specifically, a large circle in the bottom-right is not flush with the boundary, wasting valuable space, and several very small circles appear trapped in suboptimal positions. These issues suggest the Simulated Annealing (SA) search strategy can be refined to be more effective. + +The current SA algorithm heavily prioritizes moving small circles. While beneficial for fine-tuning, this makes it difficult for the algorithm to correct large-scale structural inefficiencies involving larger circles. My proposed changes aim to create a more balanced search capable of both large-scale adjustments and fine-grained refinement. + + +retune_sa_selection_and_perturbation + + +Based on the visualization, the current packing has two key weaknesses: large circles are in suboptimal positions (e.g., the large circle in the bottom-right is not flush against the boundary), and some very small circles appear trapped. These issues suggest the Simulated Annealing (SA) search could be improved. + +The current SA algorithm heavily favors selecting and moving small circles, which can prevent it from fixing large-scale structural problems. To address this, I am making two coordinated changes to the SA loop: + +1. **Re-balance Selection:** I am reducing the exponent on the inverse radius weighting for circle selection from 1.0 to 0.75. This makes the selection probability less skewed towards tiny circles and gives larger, structurally important circles a more reasonable chance to be selected and moved. This change is critical for allowing the search to fix the gross inefficiencies visible in the packing. + +2. **Boost Small-Circle Mobility:** To complement the change above and still address the issue of trapped small circles, I am increasing the adaptive perturbation multiplier from 2.0 to 2.5. This gives the smallest circles an even larger "kick", enhancing their ability to escape from tight spots and find more globally optimal locations. + +These two changes work together to create a more balanced search, capable of making both large-scale structural adjustments and fine-grained local refinements. + + +<<<<<<< SEARCH + # Adaptive Selection: Prioritize small circles and those near boundaries + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.1) + weights = inverse_radii * (1 + boundary_weight) +======= + # Adaptive Selection: Prioritize small circles and those near boundaries. + # The weighting exponent is reduced from 1.0 to 0.75 to give larger circles + # a slightly higher probability of being selected and moved, helping to resolve + # large-scale structural inefficiencies. + size_weight = (1 / (current_radii + 1e-8))**0.75 + dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.1) + weights = size_weight * (1 + boundary_weight) +>>>>>>> REPLACE + + +<<<<<<< SEARCH + # Increased multiplier for more aggressive small circle movement + perturb_factor = 1.0 + (1.0 - relative_r) * 2.0 +======= + # Increased multiplier for even more aggressive small circle movement, helping them escape tight spots. + perturb_factor = 1.0 + (1.0 - relative_r) * 2.5 +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6c633073475dee5cbe8446d206a269f5cf2ba74 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..8c72781586b71a62e69ccf03b36cd03ecc41f35e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/edit.diff @@ -0,0 +1,288 @@ +--- a/original.py ++++ b/original.py +@@ -1,180 +1,185 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" ++""" ++Constructor-based circle packing for n=26 circles using a hybrid approach: ++a force-directed pre-relaxation followed by an advanced Simulated Annealing search. ++""" + + import numpy as np + +-# This function remains largely the same as it is a robust way to evaluate a given center configuration. + def compute_max_radii(centers): + """ +- Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This is +- an iterative version that converges to a stable solution. +- +- Args: +- centers: np.array of shape (n, 2) with (x, y) coordinates +- +- Returns: +- np.array of shape (n) with radius of each circle ++ Compute the maximum possible radii for each circle position such that they ++ don't overlap and stay within the unit square. This is an iterative version ++ that converges to a stable solution. + """ + n = centers.shape[0] +- +- # Initialize radii based on distance to the square's boundaries (vectorized). ++ # Initialize radii based on distance to boundaries (vectorized) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + +- # Iteratively resolve overlaps between circles until no more changes occur. +- # A high number of iterations ensures convergence for complex arrangements. +- for _ in range(500): # Increased iterations for more thorough convergence ++ # Iteratively resolve overlaps until convergence ++ for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) +- +- # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] +- if sum_r > 1e-12: # Avoid division by zero +- # Scale both radii down proportionally to resolve the overlap. +- # This ensures the ratio of radii is maintained if possible +- # while eliminating overlap. ++ if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale +- +- # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True +- else: # If both radii are already ~0, ensure they are exactly 0 +- # Only set changes_made if they weren't already exactly 0 +- if radii[i] > 1e-12 or radii[j] > 1e-12: +- radii[i] = 0 +- radii[j] = 0 +- changes_made = True +- +- # If a full pass resulted in no changes, the packing is stable. ++ elif radii[i] > 0 or radii[j] > 0: ++ radii[i], radii[j] = 0, 0 ++ changes_made = True + if not changes_made: + break ++ return radii + +- return radii ++def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): ++ """ ++ Applies a force-directed relaxation algorithm to settle circle centers. ++ Circles repel each other and are repelled by boundaries. ++ This is adopted from a high-performing ancestor. ++ """ ++ n = centers.shape[0] ++ for _ in range(iterations): ++ forces = np.zeros_like(centers) ++ for i in range(n): ++ # Circle-circle repulsion ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ # Boundary repulsion ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) ++ centers += step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ return centers + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles using an iterative +- local search algorithm with targeted perturbations and greedy acceptance, +- starting from an asymmetric Gaussian-deformed grid. This combines the +- successful local search strategy with a robust radii computation. +- +- Returns: +- Tuple of (centers, radii) +- centers: np.array of shape (26, 2) with (x, y) coordinates +- radii: np.array of shape (26) with radius of each circle ++ Constructs a high-density arrangement of 26 circles. This method combines ++ a proven asymmetric initialization, a mild force-directed pre-relaxation, ++ and a sophisticated Simulated Annealing local search with adaptive heuristics. + """ + n = 26 + +- # 1. Initial Grid Generation (from the high-scoring prior program) ++ # 1. Initialization: Asymmetric Gaussian-deformed grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T +- +- # Asymmetric void to break symmetry and provide a starting point for rearrangement + void_center = np.array([0.4, 0.2]) +- amplitude = 0.06 # Amplitude from the high-scoring prior +- sigma = 0.15 ++ amplitude, sigma = 0.06, 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 +- + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) +- + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + +- initial_centers = np.zeros((n, 2)) +- initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- initial_centers[25] = void_center +- initial_centers = np.clip(initial_centers, 0.0, 1.0) ++ centers = np.zeros((n, 2)) ++ centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ centers[25] = void_center ++ centers = np.clip(centers, 0.0, 1.0) + +- # 2. Iterative Local Search with Simulated Annealing +- # This replaces the greedy search with SA to escape local optima, +- # inspired by the rigid structure seen in the visualization. +- best_centers = initial_centers.copy() +- best_radii = compute_max_radii(best_centers) +- best_sum_radii = np.sum(best_radii) ++ # 2. Pre-optimization: Reintroducing force-directed relaxation. ++ centers = apply_force_directed_relaxation( ++ centers, iterations=500, step_size=0.001, repulsion_strength=0.01, ++ repulsion_threshold=0.18, boundary_strength=0.05, boundary_margin=0.03 ++ ) + +- # SA requires tracking the current state, which can temporarily worsen. +- current_centers = initial_centers.copy() +- current_radii = best_radii.copy() ++ # 3. Main Optimization: Advanced Simulated Annealing with Stagnation Escape. ++ radii = compute_max_radii(centers) ++ ++ best_centers = centers.copy() ++ best_radii = radii.copy() ++ best_sum_radii = np.sum(radii) ++ ++ current_centers = centers.copy() ++ current_radii = radii.copy() + current_sum_radii = best_sum_radii + +- # Parameters inspired by high-scoring previous attempts, tuned for more exploration. +- total_iterations = 12000 +- initial_perturb_strength = 0.03 # Increased for more exploration +- final_perturb_strength = 0.0005 ++ # Tuned SA parameters from high-performing ancestors for better exploration ++ total_iterations = 15000 ++ initial_g_perturb_base = 0.04 ++ final_g_perturb = 0.0003 ++ T_initial, T_final = 0.2, 1e-7 + +- # SA Temperature Schedule +- T_initial = 0.1 # Higher temperature to accept more worse moves early on +- T_final = 1e-6 # Very low final temperature for greedy-like refinement ++ # Stagnation escape mechanism to kick search out of local optima ++ no_improvement_count = 0 ++ max_no_improvement_steps = 500 ++ current_initial_g_perturb = initial_g_perturb_base + +- for iteration in range(total_iterations): +- # Linearly decay perturbation strength +- perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) ++ for it in range(total_iterations): ++ # Annealing schedules with dynamic perturbation ++ g_perturb = current_initial_g_perturb + (final_g_perturb - current_initial_g_perturb) * (it / total_iterations) ++ temp = T_initial * (T_final / T_initial)**(it / total_iterations) + +- # Exponentially decay temperature +- temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) +- +- # Perturb from the current state, not the best state + candidate_centers = current_centers.copy() + +- # Target circles based on the current radii to guide the ongoing search ++ # Adaptive Selection: Prioritize small circles and those near boundaries + inverse_radii = 1 / (current_radii + 1e-8) +- selection_probs = inverse_radii / np.sum(inverse_radii) ++ dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0) ++ boundary_weight = np.exp(-dist_to_boundary / 0.1) ++ weights = inverse_radii * (1 + boundary_weight) ++ probs = weights / np.sum(weights) ++ circle_idx = np.random.choice(n, p=probs) + +- # Select a circle to perturb based on its probability +- circle_idx = np.random.choice(n, p=selection_probs) ++ # Adaptive Perturbation: Give larger kicks to smaller circles ++ max_r = np.max(current_radii) + 1e-8 ++ relative_r = current_radii[circle_idx] / max_r ++ perturb_factor = 1.0 + (1.0 - relative_r) * 2.0 ++ eff_perturb = g_perturb * perturb_factor + +- # Generate a random displacement for the selected circle +- displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) +- candidate_centers[circle_idx] += displacement ++ displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + +- # Clip the candidate center to remain within the unit square +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +- +- # Evaluate the new configuration ++ # Evaluation and Acceptance + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + +- # Simulated Annealing acceptance criteria +- if candidate_sum_radii > current_sum_radii: +- # Always accept a better solution ++ accepted = False ++ delta = candidate_sum_radii - current_sum_radii ++ if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() +- else: +- # Accept a worse solution with a probability dependent on temperature +- delta = candidate_sum_radii - current_sum_radii # This is negative +- if temperature > 1e-9: # Avoid division by zero +- acceptance_prob = np.exp(delta / temperature) +- if np.random.rand() < acceptance_prob: +- current_sum_radii = candidate_sum_radii +- current_centers = candidate_centers.copy() +- current_radii = candidate_radii.copy() ++ accepted = True + +- # Update the globally best solution found so far ++ # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() ++ no_improvement_count = 0 # Reset on new best ++ elif not accepted: ++ no_improvement_count += 1 ++ # If stagnated, boost perturbation to escape local optimum ++ if no_improvement_count > max_no_improvement_steps: ++ current_initial_g_perturb *= 1.2 ++ no_improvement_count = 0 + + return best_centers, best_radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/main.py new file mode 100644 index 0000000000000000000000000000000000000000..882cc999c4f221b221339501c0bf617f6392d12c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/main.py @@ -0,0 +1,185 @@ +# EVOLVE-BLOCK-START +""" +Constructor-based circle packing for n=26 circles using a hybrid approach: +a force-directed pre-relaxation followed by an advanced Simulated Annealing search. +""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + """ + n = centers.shape[0] + # Initialize radii based on distance to boundaries (vectorized) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps until convergence + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + This is adopted from a high-performing ancestor. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles. This method combines + a proven asymmetric initialization, a mild force-directed pre-relaxation, + and a sophisticated Simulated Annealing local search with adaptive heuristics. + """ + n = 26 + + # 1. Initialization: Asymmetric Gaussian-deformed grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + void_center = np.array([0.4, 0.2]) + amplitude, sigma = 0.06, 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 2. Pre-optimization: Reintroducing force-directed relaxation. + centers = apply_force_directed_relaxation( + centers, iterations=500, step_size=0.001, repulsion_strength=0.01, + repulsion_threshold=0.18, boundary_strength=0.05, boundary_margin=0.03 + ) + + # 3. Main Optimization: Advanced Simulated Annealing with Stagnation Escape. + radii = compute_max_radii(centers) + + best_centers = centers.copy() + best_radii = radii.copy() + best_sum_radii = np.sum(radii) + + current_centers = centers.copy() + current_radii = radii.copy() + current_sum_radii = best_sum_radii + + # Tuned SA parameters from high-performing ancestors for better exploration + total_iterations = 15000 + initial_g_perturb_base = 0.04 + final_g_perturb = 0.0003 + T_initial, T_final = 0.2, 1e-7 + + # Stagnation escape mechanism to kick search out of local optima + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_g_perturb = initial_g_perturb_base + + for it in range(total_iterations): + # Annealing schedules with dynamic perturbation + g_perturb = current_initial_g_perturb + (final_g_perturb - current_initial_g_perturb) * (it / total_iterations) + temp = T_initial * (T_final / T_initial)**(it / total_iterations) + + candidate_centers = current_centers.copy() + + # Adaptive Selection: Prioritize small circles and those near boundaries + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.1) + weights = inverse_radii * (1 + boundary_weight) + probs = weights / np.sum(weights) + circle_idx = np.random.choice(n, p=probs) + + # Adaptive Perturbation: Give larger kicks to smaller circles + max_r = np.max(current_radii) + 1e-8 + relative_r = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_r) * 2.0 + eff_perturb = g_perturb * perturb_factor + + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluation and Acceptance + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + accepted = False + delta = candidate_sum_radii - current_sum_radii + if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best + elif not accepted: + no_improvement_count += 1 + # If stagnated, boost perturbation to escape local optimum + if no_improvement_count > max_no_improvement_steps: + current_initial_g_perturb *= 1.2 + no_improvement_count = 0 + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/original.py new file mode 100644 index 0000000000000000000000000000000000000000..62fbc9cb9eae9763e2d8e9a0a320a436c9b80e97 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/original.py @@ -0,0 +1,180 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + +# This function remains largely the same as it is a robust way to evaluate a given center configuration. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + # This ensures the ratio of radii is maintained if possible + # while eliminating overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + # Only set changes_made if they weren't already exactly 0 + if radii[i] > 1e-12 or radii[j] > 1e-12: + radii[i] = 0 + radii[j] = 0 + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using an iterative + local search algorithm with targeted perturbations and greedy acceptance, + starting from an asymmetric Gaussian-deformed grid. This combines the + successful local search strategy with a robust radii computation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # 1. Initial Grid Generation (from the high-scoring prior program) + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Asymmetric void to break symmetry and provide a starting point for rearrangement + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 # Amplitude from the high-scoring prior + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + initial_centers = np.clip(initial_centers, 0.0, 1.0) + + # 2. Iterative Local Search with Simulated Annealing + # This replaces the greedy search with SA to escape local optima, + # inspired by the rigid structure seen in the visualization. + best_centers = initial_centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + # SA requires tracking the current state, which can temporarily worsen. + current_centers = initial_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Parameters inspired by high-scoring previous attempts, tuned for more exploration. + total_iterations = 12000 + initial_perturb_strength = 0.03 # Increased for more exploration + final_perturb_strength = 0.0005 + + # SA Temperature Schedule + T_initial = 0.1 # Higher temperature to accept more worse moves early on + T_final = 1e-6 # Very low final temperature for greedy-like refinement + + for iteration in range(total_iterations): + # Linearly decay perturbation strength + perturb_strength = initial_perturb_strength * (1 - iteration / total_iterations) + final_perturb_strength * (iteration / total_iterations) + + # Exponentially decay temperature + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + # Perturb from the current state, not the best state + candidate_centers = current_centers.copy() + + # Target circles based on the current radii to guide the ongoing search + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # Select a circle to perturb based on its probability + circle_idx = np.random.choice(n, p=selection_probs) + + # Generate a random displacement for the selected circle + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + # Clip the candidate center to remain within the unit square + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + if candidate_sum_radii > current_sum_radii: + # Always accept a better solution + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + else: + # Accept a worse solution with a probability dependent on temperature + delta = candidate_sum_radii - current_sum_radii # This is negative + if temperature > 1e-9: # Avoid division by zero + acceptance_prob = np.exp(delta / temperature) + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + + # Update the globally best solution found so far + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..88810aee5ef8d169e7c9e2858cda3deb66e3436c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_160/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_160/results +Run 1/1 completed in 33.12 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.282762965516529 + public: {'centers_str': ' centers[0] = (0.4102, 0.3199)\n centers[1] = (0.6032, 0.1220)\n centers[2] = (0.4603, 0.5677)\n centers[3] = (0.1094, 0.2768)\n centers[4] = (0.2766, 0.9236)\n centers[5] = (0.1277, 0.0843)\n centers[6] = (0.0573, 0.7728)\n centers[7] = (0.0762, 0.4582)\n centers[8] = (0.7774, 0.9639)\n centers[9] = (0.8138, 0.1339)\n centers[10] = (0.3824, 0.6547)\n centers[11] = (0.9270, 0.3070)\n centers[12] = (0.8030, 0.5288)\n centers[13] = (0.7451, 0.7093)\n centers[14] = (0.6058, 0.3699)\n centers[15] = (0.3047, 0.4545)\n centers[16] = (0.0962, 0.9124)\n centers[17] = (0.4754, 0.8632)\n centers[18] = (0.9425, 0.5535)\n centers[19] = (0.6896, 0.8977)\n centers[20] = (0.9220, 0.6859)\n centers[21] = (0.0962, 0.6262)\n centers[22] = (0.5536, 0.6375)\n centers[23] = (0.2441, 0.7752)\n centers[24] = (0.8860, 0.8743)\n centers[25] = (0.3585, 0.1569)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.282762965516529} + visualization_path: + execution_time_mean: 33.12335807830095 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..671d914621bab0dab6f616cad7d9ae1cb0b6cd39 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.282762965516529, + "public": { + "centers_str": " centers[0] = (0.4102, 0.3199)\n centers[1] = (0.6032, 0.1220)\n centers[2] = (0.4603, 0.5677)\n centers[3] = (0.1094, 0.2768)\n centers[4] = (0.2766, 0.9236)\n centers[5] = (0.1277, 0.0843)\n centers[6] = (0.0573, 0.7728)\n centers[7] = (0.0762, 0.4582)\n centers[8] = (0.7774, 0.9639)\n centers[9] = (0.8138, 0.1339)\n centers[10] = (0.3824, 0.6547)\n centers[11] = (0.9270, 0.3070)\n centers[12] = (0.8030, 0.5288)\n centers[13] = (0.7451, 0.7093)\n centers[14] = (0.6058, 0.3699)\n centers[15] = (0.3047, 0.4545)\n centers[16] = (0.0962, 0.9124)\n centers[17] = (0.4754, 0.8632)\n centers[18] = (0.9425, 0.5535)\n centers[19] = (0.6896, 0.8977)\n centers[20] = (0.9220, 0.6859)\n centers[21] = (0.0962, 0.6262)\n centers[22] = (0.5536, 0.6375)\n centers[23] = (0.2441, 0.7752)\n centers[24] = (0.8860, 0.8743)\n centers[25] = (0.3585, 0.1569)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.282762965516529 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_160/results/packing_viz.png", + "execution_time_mean": 33.12335807830095, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..944b07f4bc47bb6fff5840cf667458c9bc46401b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_160/rewrite.txt @@ -0,0 +1,176 @@ +# EVOLVE-BLOCK-START +""" +Constructor-based circle packing for n=26 circles using a hybrid approach: +a force-directed pre-relaxation followed by an advanced Simulated Annealing search. +""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + """ + n = centers.shape[0] + # Initialize radii based on distance to boundaries (vectorized) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps until convergence + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + This is adopted from a high-performing ancestor. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles. This method combines + a proven asymmetric initialization, a mild force-directed pre-relaxation, + and a sophisticated Simulated Annealing local search with adaptive heuristics. + """ + n = 26 + + # 1. Initialization: Asymmetric Gaussian-deformed grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + void_center = np.array([0.4, 0.2]) + amplitude, sigma = 0.06, 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 2. Pre-optimization: Reintroducing force-directed relaxation. + centers = apply_force_directed_relaxation( + centers, iterations=500, step_size=0.001, repulsion_strength=0.01, + repulsion_threshold=0.18, boundary_strength=0.05, boundary_margin=0.03 + ) + + # 3. Main Optimization: Advanced Simulated Annealing with Stagnation Escape. + radii = compute_max_radii(centers) + + best_centers = centers.copy() + best_radii = radii.copy() + best_sum_radii = np.sum(radii) + + current_centers = centers.copy() + current_radii = radii.copy() + current_sum_radii = best_sum_radii + + # Tuned SA parameters from high-performing ancestors for better exploration + total_iterations = 15000 + initial_g_perturb_base = 0.04 + final_g_perturb = 0.0003 + T_initial, T_final = 0.2, 1e-7 + + # Stagnation escape mechanism to kick search out of local optima + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_g_perturb = initial_g_perturb_base + + for it in range(total_iterations): + # Annealing schedules with dynamic perturbation + g_perturb = current_initial_g_perturb + (final_g_perturb - current_initial_g_perturb) * (it / total_iterations) + temp = T_initial * (T_final / T_initial)**(it / total_iterations) + + candidate_centers = current_centers.copy() + + # Adaptive Selection: Prioritize small circles and those near boundaries + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.1) + weights = inverse_radii * (1 + boundary_weight) + probs = weights / np.sum(weights) + circle_idx = np.random.choice(n, p=probs) + + # Adaptive Perturbation: Give larger kicks to smaller circles + max_r = np.max(current_radii) + 1e-8 + relative_r = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_r) * 2.0 + eff_perturb = g_perturb * perturb_factor + + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluation and Acceptance + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + accepted = False + delta = candidate_sum_radii - current_sum_radii + if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best + elif not accepted: + no_improvement_count += 1 + # If stagnated, boost perturbation to escape local optimum + if no_improvement_count > max_no_improvement_steps: + current_initial_g_perturb *= 1.2 + no_improvement_count = 0 + + return best_centers, best_radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e86bd9bb254474469714c7ee6cfe2c8b6f3c22bb Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..7ea9bc0c700c0875a6433845159af2fc4b006328 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_164/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_164/results +Run 1/1 completed in 67.13 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.2363533452366697 + public: {'centers_str': ' centers[0] = (0.7556, 0.0393)\n centers[1] = (0.6133, 0.6857)\n centers[2] = (0.8681, 0.3370)\n centers[3] = (0.3084, 0.4755)\n centers[4] = (0.2269, 0.2783)\n centers[5] = (0.8974, 0.1086)\n centers[6] = (0.1421, 0.8077)\n centers[7] = (0.5746, 0.0423)\n centers[8] = (0.0941, 0.4274)\n centers[9] = (0.3826, 0.8884)\n centers[10] = (0.6793, 0.1708)\n centers[11] = (0.0792, 0.5956)\n centers[12] = (0.2209, 0.0774)\n centers[13] = (0.3146, 0.2814)\n centers[14] = (0.0405, 0.9596)\n centers[15] = (0.4237, 0.1341)\n centers[16] = (0.5934, 0.4527)\n centers[17] = (0.8130, 0.9463)\n centers[18] = (0.8394, 0.6273)\n centers[19] = (0.2557, 0.4050)\n centers[20] = (0.9147, 0.8511)\n centers[21] = (0.2766, 0.5904)\n centers[22] = (0.1025, 0.2124)\n centers[23] = (0.4770, 0.6875)\n centers[24] = (0.6434, 0.8659)\n centers[25] = (0.3933, 0.3468)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.2363533452366697} + visualization_path: + execution_time_mean: 67.13286555092782 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..2ed0900ac115cb5f27b24806a20dedd6218d77ce --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.2363533452366697, + "public": { + "centers_str": " centers[0] = (0.7556, 0.0393)\n centers[1] = (0.6133, 0.6857)\n centers[2] = (0.8681, 0.3370)\n centers[3] = (0.3084, 0.4755)\n centers[4] = (0.2269, 0.2783)\n centers[5] = (0.8974, 0.1086)\n centers[6] = (0.1421, 0.8077)\n centers[7] = (0.5746, 0.0423)\n centers[8] = (0.0941, 0.4274)\n centers[9] = (0.3826, 0.8884)\n centers[10] = (0.6793, 0.1708)\n centers[11] = (0.0792, 0.5956)\n centers[12] = (0.2209, 0.0774)\n centers[13] = (0.3146, 0.2814)\n centers[14] = (0.0405, 0.9596)\n centers[15] = (0.4237, 0.1341)\n centers[16] = (0.5934, 0.4527)\n centers[17] = (0.8130, 0.9463)\n centers[18] = (0.8394, 0.6273)\n centers[19] = (0.2557, 0.4050)\n centers[20] = (0.9147, 0.8511)\n centers[21] = (0.2766, 0.5904)\n centers[22] = (0.1025, 0.2124)\n centers[23] = (0.4770, 0.6875)\n centers[24] = (0.6434, 0.8659)\n centers[25] = (0.3933, 0.3468)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.2363533452366697 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_164/results/packing_viz.png", + "execution_time_mean": 67.13286555092782, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..68b338c741340390ec8d75c9cf75b5d03f6d4177 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..f5f5fcccc81c3c449ee86a08918eb05ab2360516 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/edit.diff @@ -0,0 +1,445 @@ +--- a/original.py ++++ b/original.py +@@ -1,288 +1,198 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles using Modular Simulated Annealing local search""" +- + import numpy as np ++from scipy.spatial import Voronoi + + def compute_max_radii(centers): + """ +- Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This is +- an iterative version that converges to a stable solution. +- +- Args: +- centers: np.array of shape (n, 2) with (x, y) coordinates +- +- Returns: +- np.array of shape (n) with radius of each circle ++ Compute the maximum possible radii for each circle position such that they ++ don't overlap and stay within the unit square. This is an iterative version ++ that converges to a stable solution. + """ + n = centers.shape[0] +- +- # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + +- # Iteratively resolve overlaps between circles until no more changes occur. +- # A high number of iterations ensures convergence for complex arrangements. +- for _ in range(500): # Increased iterations for more thorough convergence ++ for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) +- +- # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] +- if sum_r > 1e-12: # Avoid division by zero +- # Scale both radii down proportionally to resolve the overlap. ++ if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale +- +- # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True +- else: # If both radii are already ~0, ensure they are exactly 0 +- # Only set changes_made if they weren't already exactly 0 +- if radii[i] > 1e-12 or radii[j] > 1e-12: +- radii[i] = 0 +- radii[j] = 0 +- changes_made = True +- +- # If a full pass resulted in no changes, the packing is stable. ++ elif radii[i] > 0 or radii[j] > 0: ++ radii[i], radii[j] = 0, 0 ++ changes_made = True + if not changes_made: + break +- + return radii + +-class CirclePacker: +- """ +- Encapsulates the logic for constructing a high-density arrangement of circles +- using an asymmetric grid initialization, a pre-optimization force-directed +- relaxation, and a Simulated Annealing local search with adaptive perturbations. +- """ +- def __init__(self, n): +- self.n = n +- self.centers = np.zeros((n, 2)) +- self.radii = np.zeros(n) +- self.sum_radii = 0.0 ++def polygon_centroid(vertices): ++ """Calculates the centroid of a polygon given its vertices.""" ++ A = 0.0 ++ C_x, C_y = 0.0, 0.0 ++ num_vertices = len(vertices) ++ if num_vertices == 0: ++ # Should not happen with valid regions, but return a central point as a fallback ++ return np.array([0.5, 0.5]) + +- def _initialize_centers(self): +- """ +- Initializes circle centers using a Gaussian-deformed grid for 25 circles +- and places the 26th in an asymmetric void. +- """ +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T ++ for i in range(num_vertices): ++ x_i, y_i = vertices[i] ++ x_j, y_j = vertices[(i + 1) % num_vertices] ++ ++ cross_product = (x_i * y_j - x_j * y_i) ++ A += cross_product ++ C_x += (x_i + x_j) * cross_product ++ C_y += (y_i + y_j) * cross_product + +- # Asymmetric void adjusted to (0.4, 0.2) based on previous high-performing results. +- void_center = np.array([0.4, 0.2]) +- amplitude = 0.06 # Reverted to 0.06 for a slightly less aggressive initial void creation. +- sigma = 0.15 ++ if abs(A) < 1e-9: ++ # Fallback for degenerate polygons (e.g., a line) ++ return np.mean(vertices, axis=0) ++ ++ signed_area = A * 0.5 ++ C_x /= (6.0 * signed_area) ++ C_y /= (6.0 * signed_area) ++ ++ return np.array([C_x, C_y]) + +- displacements = base_centers_25 - void_center +- distances = np.linalg.norm(displacements, axis=1) +- mask = distances > 1e-9 ++def voronoi_relaxation_step(centers, alpha): ++ """Performs one step of Lloyd's relaxation, moving centers towards their Voronoi centroids.""" ++ n = centers.shape[0] ++ ++ # Create ghost points by reflecting across boundaries to handle bounded Voronoi cells ++ # This is more robust than manual polygon clipping. ++ ghost_reflections = [ ++ centers * np.array([-1, 1]), # x=0 ++ centers * np.array([1, -1]), # y=0 ++ centers * np.array([-1, -1]), # corner 0,0 ++ np.array([2, 1]) - centers * np.array([-1, 1]), # x=1 ++ np.array([1, 2]) - centers * np.array([1, -1]), # y=1 ++ np.array([2, 2]) - centers, # corner 1,1 ++ np.array([0, 2]) - centers * np.array([-1, -1]), # corner 0,1 ++ np.array([2, 0]) - centers * np.array([-1, -1]) # corner 1,0 ++ ] ++ all_points = np.vstack([centers] + ghost_reflections) + +- push_magnitudes = np.zeros(25) +- push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ try: ++ vor = Voronoi(all_points, qhull_options='Qbb Qc Qx') ++ except Exception: # Catch Qhull errors if points are degenerate ++ return centers # On failure, return original centers (no move) + +- if np.any(mask): +- displacements[mask] /= distances[mask, np.newaxis] ++ new_centers = np.copy(centers) ++ for i in range(n): ++ region_idx = vor.point_region[i] ++ # Ensure region is valid and bounded ++ if region_idx == -1 or not vor.regions[region_idx] or -1 in vor.regions[region_idx]: ++ continue ++ ++ region_vertices = vor.vertices[vor.regions[region_idx]] ++ centroid = polygon_centroid(region_vertices) ++ ++ # Move the center towards the centroid by a factor of alpha ++ direction = centroid - centers[i] ++ new_centers[i] += alpha * direction + +- self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- self.centers[25] = void_center +- self.centers = np.clip(self.centers, 0.0, 1.0) # Ensure centers are within [0,1] square +- self.radii = compute_max_radii(self.centers) +- self.sum_radii = np.sum(self.radii) +- +- def _apply_force_directed_relaxation(self, centers_to_relax, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): +- """ +- Applies a force-directed relaxation algorithm to a set of circle centers. +- Circles repel each other and are repelled by boundaries. +- """ +- n_local = centers_to_relax.shape[0] +- for _ in range(iterations): +- forces = np.zeros_like(centers_to_relax) +- +- # Circle-circle repulsion +- for i in range(n_local): +- for j in range(i + 1, n_local): +- vec = centers_to_relax[i] - centers_to_relax[j] +- dist = np.linalg.norm(vec) +- # Increased repulsion threshold to encourage more spacing initially +- if 0 < dist < repulsion_threshold: +- force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist +- force_vec = force_magnitude * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- +- # Boundary repulsion +- for i in range(n_local): +- x, y = centers_to_relax[i] +- # Increased boundary strength to push centers closer to edges +- if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) +- +- centers_to_relax += step_size * forces +- centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) # Keep centers within bounds +- return centers_to_relax +- +- def _select_circle_for_perturbation(self, current_radii, current_centers): +- """ +- Selects a circle to perturb based on its inverse radius and proximity to boundaries. +- Smaller circles and those closer to boundaries have a higher chance of being selected. +- """ +- inverse_radii = 1 / (current_radii + 1e-8) +- +- # Calculate distance to nearest boundary for each circle +- dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], +- current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) +- +- # Exponentially weight circles closer to boundaries +- # Reduced scale factor (0.07) to make boundary proximity more influential. +- boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) +- +- # Combine inverse_radii and boundary proximity to get selection weights +- combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) +- selection_probs = combined_weights / np.sum(combined_weights) +- +- circle_idx = np.random.choice(self.n, p=selection_probs) +- return circle_idx +- +- def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): +- """ +- Calculates an adaptive perturbation strength for a specific circle. +- Smaller circles receive a proportionally larger perturbation to help them +- escape local minima. +- """ +- max_r = np.max(current_radii) + 1e-8 # Avoid division by zero +- relative_radius = current_radii[circle_idx] / max_r +- +- # Perturbation factor: 1.0 for the largest circle, up to 3.0 for the smallest. +- # Increased multiplier (2.0) for more aggressive movement of small circles. +- perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 +- +- return global_perturb_strength * perturb_factor +- +- def pack(self): +- """ +- Executes the full packing process: initialization, pre-optimization, +- and Simulated Annealing. +- """ +- self._initialize_centers() +- +- # Pre-optimization with a more robust Force-Directed Relaxation stage. +- # A stronger initial relaxation helps create a more uniform starting point for SA. +- self.centers = self._apply_force_directed_relaxation( +- self.centers.copy(), +- iterations=600, # Increased iterations for more thorough settling +- step_size=0.001, +- repulsion_strength=0.01, +- repulsion_threshold=0.20, # Increased threshold for more initial spacing +- boundary_strength=0.05, +- boundary_margin=0.03 +- ) +- self.radii = compute_max_radii(self.centers) +- self.sum_radii = np.sum(self.radii) +- +- # Initialize current and best states for Simulated Annealing +- best_centers = self.centers.copy() +- best_radii = self.radii.copy() +- best_sum_radii = self.sum_radii +- +- current_centers = self.centers.copy() +- current_radii = self.radii.copy() +- current_sum_radii = self.sum_radii +- +- total_iterations = 15000 # Increased total iterations for thorough SA search +- initial_global_perturb_strength_base = 0.04 # Base initial perturbation for more exploration. +- final_global_perturb_strength = 0.0003 # Slightly lower final for finer tuning. +- +- T_initial = 0.2 # Increased initial temperature to accept more "worse" moves initially. +- T_final = 1e-7 # Even lower final temperature for very greedy behavior at the end. +- +- # Counter for progress-sensitive adaptive perturbation strength +- no_improvement_count = 0 +- max_no_improvement_steps = 500 # If no improvement for this many steps, boost initial perturb_strength +- +- # Use a mutable variable for current initial_global_perturb_strength +- current_initial_global_perturb_strength = initial_global_perturb_strength_base +- +- for iteration in range(total_iterations): +- # Linearly decay global perturbation strength +- global_perturb_strength = current_initial_global_perturb_strength * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) +- +- # Exponentially decay temperature +- temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) +- +- candidate_centers = current_centers.copy() +- +- # Select a circle to perturb using adaptive selection criteria +- circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) +- +- # Determine perturbation strength dynamically for the selected circle +- effective_perturb_strength = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) +- +- # Generate and apply displacement +- displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +- candidate_centers[circle_idx] += displacement +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +- +- # Evaluate the candidate configuration +- candidate_radii = compute_max_radii(candidate_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- # Simulated Annealing acceptance criteria +- accepted = False +- if candidate_sum_radii > current_sum_radii: +- # Always accept better solutions +- current_sum_radii = candidate_sum_radii +- current_centers = candidate_centers.copy() +- current_radii = candidate_radii.copy() +- accepted = True +- else: +- # Accept worse solutions with a probability based on temperature +- delta = candidate_sum_radii - current_sum_radii # Will be negative or zero +- acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 +- +- if np.random.rand() < acceptance_prob: +- current_sum_radii = candidate_sum_radii +- current_centers = candidate_centers.copy() +- current_radii = candidate_radii.copy() +- accepted = True +- +- # Update the globally best solution found so far +- if current_sum_radii > best_sum_radii: +- best_sum_radii = current_sum_radii +- best_centers = current_centers.copy() +- best_radii = current_radii.copy() +- no_improvement_count = 0 # Reset counter on new best +- elif not accepted: # If not accepted and not better +- no_improvement_count += 1 +- # Adaptive adjustment: If stuck, temporarily boost perturbation to escape +- if no_improvement_count > max_no_improvement_steps: +- current_initial_global_perturb_strength *= 1.2 # Boost initial strength +- no_improvement_count = 0 # Reset counter +- +- return best_centers, best_radii ++ return new_centers + + def construct_packing(): + """ +- Main function to construct the circle packing. +- Initializes CirclePacker and runs its packing method. ++ Constructs a high-density arrangement of 26 circles using a hybrid of ++ Voronoi-based Lloyd's Relaxation and Simulated Annealing. + """ +- packer = CirclePacker(n=26) +- return packer.pack() ++ n = 26 ++ ++ # 1. Initialization: Asymmetric Gaussian-deformed grid from high-performing ancestors. ++ x_coords = np.linspace(0.1, 0.9, 5) ++ y_coords = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords, y_coords) ++ base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T ++ void_center = np.array([0.4, 0.2]) ++ amplitude, sigma = 0.06, 0.15 ++ ++ displacements = base_centers_25 - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ mask = distances > 1e-9 ++ push_magnitudes = np.zeros(25) ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ displacements[mask] /= distances[mask, np.newaxis] ++ ++ centers = np.zeros((n, 2)) ++ centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ centers[25] = void_center ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ radii = compute_max_radii(centers) ++ best_centers = centers.copy() ++ best_radii = radii.copy() ++ best_sum_radii = np.sum(radii) ++ ++ current_centers = centers.copy() ++ current_radii = radii.copy() ++ current_sum_radii = best_sum_radii ++ ++ # 2. Main Optimization: Hybrid Voronoi-SA Search ++ total_iterations = 3000 # Fewer iterations as Voronoi steps are more powerful ++ T_initial, T_final = 0.1, 1e-8 ++ ++ # Annealing schedule for Lloyd's relaxation step size ++ alpha_initial, alpha_final = 0.8, 0.05 ++ ++ # Probability of performing a classic stochastic move instead of Voronoi relaxation ++ stochastic_move_prob = 0.15 ++ ++ for it in range(total_iterations): ++ # Annealing schedules ++ temp = T_initial * (T_final / T_initial)**(it / total_iterations) ++ alpha = alpha_initial * (alpha_final / alpha_initial)**(it / total_iterations) ++ ++ candidate_centers = current_centers.copy() ++ ++ if np.random.rand() < stochastic_move_prob: ++ # Stochastic Move: Perturb a single circle (helps escape Lloyd's minima) ++ # Prioritize small circles for this kick ++ inverse_radii = 1 / (current_radii + 1e-8) ++ probs = inverse_radii / np.sum(inverse_radii) ++ circle_idx = np.random.choice(n, p=probs) ++ ++ perturb_strength = 0.05 * (1 - it / total_iterations) # Simple annealing perturbation ++ displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ ++ else: ++ # Voronoi Relaxation Move: Apply one step of Lloyd's algorithm ++ candidate_centers = voronoi_relaxation_step(current_centers, alpha) ++ ++ # Clip all centers to ensure they are within the unit square ++ candidate_centers = np.clip(candidate_centers, 0.0, 1.0) ++ ++ # 3. Evaluation and Acceptance ++ candidate_radii = compute_max_radii(candidate_centers) ++ candidate_sum_radii = np.sum(candidate_radii) ++ ++ delta = candidate_sum_radii - current_sum_radii ++ if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers.copy() ++ current_radii = candidate_radii.copy() ++ ++ # Update best solution found so far ++ if current_sum_radii > best_sum_radii: ++ best_sum_radii = current_sum_radii ++ best_centers = current_centers.copy() ++ best_radii = current_radii.copy() ++ ++ return best_centers, best_radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/main.py new file mode 100644 index 0000000000000000000000000000000000000000..20e39a4ef3b6e29a44ea44ae787743e7ac9d3f39 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/main.py @@ -0,0 +1,198 @@ +# EVOLVE-BLOCK-START +import numpy as np +from scipy.spatial import Voronoi + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def polygon_centroid(vertices): + """Calculates the centroid of a polygon given its vertices.""" + A = 0.0 + C_x, C_y = 0.0, 0.0 + num_vertices = len(vertices) + if num_vertices == 0: + # Should not happen with valid regions, but return a central point as a fallback + return np.array([0.5, 0.5]) + + for i in range(num_vertices): + x_i, y_i = vertices[i] + x_j, y_j = vertices[(i + 1) % num_vertices] + + cross_product = (x_i * y_j - x_j * y_i) + A += cross_product + C_x += (x_i + x_j) * cross_product + C_y += (y_i + y_j) * cross_product + + if abs(A) < 1e-9: + # Fallback for degenerate polygons (e.g., a line) + return np.mean(vertices, axis=0) + + signed_area = A * 0.5 + C_x /= (6.0 * signed_area) + C_y /= (6.0 * signed_area) + + return np.array([C_x, C_y]) + +def voronoi_relaxation_step(centers, alpha): + """Performs one step of Lloyd's relaxation, moving centers towards their Voronoi centroids.""" + n = centers.shape[0] + + # Create ghost points by reflecting across boundaries to handle bounded Voronoi cells + # This is more robust than manual polygon clipping. + ghost_reflections = [ + centers * np.array([-1, 1]), # x=0 + centers * np.array([1, -1]), # y=0 + centers * np.array([-1, -1]), # corner 0,0 + np.array([2, 1]) - centers * np.array([-1, 1]), # x=1 + np.array([1, 2]) - centers * np.array([1, -1]), # y=1 + np.array([2, 2]) - centers, # corner 1,1 + np.array([0, 2]) - centers * np.array([-1, -1]), # corner 0,1 + np.array([2, 0]) - centers * np.array([-1, -1]) # corner 1,0 + ] + all_points = np.vstack([centers] + ghost_reflections) + + try: + vor = Voronoi(all_points, qhull_options='Qbb Qc Qx') + except Exception: # Catch Qhull errors if points are degenerate + return centers # On failure, return original centers (no move) + + new_centers = np.copy(centers) + for i in range(n): + region_idx = vor.point_region[i] + # Ensure region is valid and bounded + if region_idx == -1 or not vor.regions[region_idx] or -1 in vor.regions[region_idx]: + continue + + region_vertices = vor.vertices[vor.regions[region_idx]] + centroid = polygon_centroid(region_vertices) + + # Move the center towards the centroid by a factor of alpha + direction = centroid - centers[i] + new_centers[i] += alpha * direction + + return new_centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a hybrid of + Voronoi-based Lloyd's Relaxation and Simulated Annealing. + """ + n = 26 + + # 1. Initialization: Asymmetric Gaussian-deformed grid from high-performing ancestors. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + void_center = np.array([0.4, 0.2]) + amplitude, sigma = 0.06, 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + radii = compute_max_radii(centers) + best_centers = centers.copy() + best_radii = radii.copy() + best_sum_radii = np.sum(radii) + + current_centers = centers.copy() + current_radii = radii.copy() + current_sum_radii = best_sum_radii + + # 2. Main Optimization: Hybrid Voronoi-SA Search + total_iterations = 3000 # Fewer iterations as Voronoi steps are more powerful + T_initial, T_final = 0.1, 1e-8 + + # Annealing schedule for Lloyd's relaxation step size + alpha_initial, alpha_final = 0.8, 0.05 + + # Probability of performing a classic stochastic move instead of Voronoi relaxation + stochastic_move_prob = 0.15 + + for it in range(total_iterations): + # Annealing schedules + temp = T_initial * (T_final / T_initial)**(it / total_iterations) + alpha = alpha_initial * (alpha_final / alpha_initial)**(it / total_iterations) + + candidate_centers = current_centers.copy() + + if np.random.rand() < stochastic_move_prob: + # Stochastic Move: Perturb a single circle (helps escape Lloyd's minima) + # Prioritize small circles for this kick + inverse_radii = 1 / (current_radii + 1e-8) + probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(n, p=probs) + + perturb_strength = 0.05 * (1 - it / total_iterations) # Simple annealing perturbation + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + else: + # Voronoi Relaxation Move: Apply one step of Lloyd's algorithm + candidate_centers = voronoi_relaxation_step(current_centers, alpha) + + # Clip all centers to ensure they are within the unit square + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + + # 3. Evaluation and Acceptance + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta = candidate_sum_radii - current_sum_radii + if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + + # Update best solution found so far + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/original.py new file mode 100644 index 0000000000000000000000000000000000000000..9f87c2e51b423a02e86c5e2a52aa3ef530bc07ba --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/original.py @@ -0,0 +1,288 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using Modular Simulated Annealing local search""" + +import numpy as np + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + # Only set changes_made if they weren't already exactly 0 + if radii[i] > 1e-12 or radii[j] > 1e-12: + radii[i] = 0 + radii[j] = 0 + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Asymmetric void adjusted to (0.4, 0.2) based on previous high-performing results. + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 # Reverted to 0.06 for a slightly less aggressive initial void creation. + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) # Ensure centers are within [0,1] square + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _apply_force_directed_relaxation(self, centers_to_relax, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to a set of circle centers. + Circles repel each other and are repelled by boundaries. + """ + n_local = centers_to_relax.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers_to_relax) + + # Circle-circle repulsion + for i in range(n_local): + for j in range(i + 1, n_local): + vec = centers_to_relax[i] - centers_to_relax[j] + dist = np.linalg.norm(vec) + # Increased repulsion threshold to encourage more spacing initially + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n_local): + x, y = centers_to_relax[i] + # Increased boundary strength to push centers closer to edges + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + centers_to_relax += step_size * forces + centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) # Keep centers within bounds + return centers_to_relax + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius and proximity to boundaries. + Smaller circles and those closer to boundaries have a higher chance of being selected. + """ + inverse_radii = 1 / (current_radii + 1e-8) + + # Calculate distance to nearest boundary for each circle + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + + # Exponentially weight circles closer to boundaries + # Reduced scale factor (0.07) to make boundary proximity more influential. + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Combine inverse_radii and boundary proximity to get selection weights + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) + selection_probs = combined_weights / np.sum(combined_weights) + + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation to help them + escape local minima. + """ + max_r = np.max(current_radii) + 1e-8 # Avoid division by zero + relative_radius = current_radii[circle_idx] / max_r + + # Perturbation factor: 1.0 for the largest circle, up to 3.0 for the smallest. + # Increased multiplier (2.0) for more aggressive movement of small circles. + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 + + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing. + """ + self._initialize_centers() + + # Pre-optimization with a more robust Force-Directed Relaxation stage. + # A stronger initial relaxation helps create a more uniform starting point for SA. + self.centers = self._apply_force_directed_relaxation( + self.centers.copy(), + iterations=600, # Increased iterations for more thorough settling + step_size=0.001, + repulsion_strength=0.01, + repulsion_threshold=0.20, # Increased threshold for more initial spacing + boundary_strength=0.05, + boundary_margin=0.03 + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + # Initialize current and best states for Simulated Annealing + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + total_iterations = 15000 # Increased total iterations for thorough SA search + initial_global_perturb_strength_base = 0.04 # Base initial perturbation for more exploration. + final_global_perturb_strength = 0.0003 # Slightly lower final for finer tuning. + + T_initial = 0.2 # Increased initial temperature to accept more "worse" moves initially. + T_final = 1e-7 # Even lower final temperature for very greedy behavior at the end. + + # Counter for progress-sensitive adaptive perturbation strength + no_improvement_count = 0 + max_no_improvement_steps = 500 # If no improvement for this many steps, boost initial perturb_strength + + # Use a mutable variable for current initial_global_perturb_strength + current_initial_global_perturb_strength = initial_global_perturb_strength_base + + for iteration in range(total_iterations): + # Linearly decay global perturbation strength + global_perturb_strength = current_initial_global_perturb_strength * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + + # Exponentially decay temperature + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + # Select a circle to perturb using adaptive selection criteria + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + + # Determine perturbation strength dynamically for the selected circle + effective_perturb_strength = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + + # Generate and apply displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Evaluate the candidate configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + # Always accept better solutions + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + # Accept worse solutions with a probability based on temperature + delta = candidate_sum_radii - current_sum_radii # Will be negative or zero + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update the globally best solution found so far + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset counter on new best + elif not accepted: # If not accepted and not better + no_improvement_count += 1 + # Adaptive adjustment: If stuck, temporarily boost perturbation to escape + if no_improvement_count > max_no_improvement_steps: + current_initial_global_perturb_strength *= 1.2 # Boost initial strength + no_improvement_count = 0 # Reset counter + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePacker and runs its packing method. + """ + packer = CirclePacker(n=26) + return packer.pack() +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..d1274d6fb863daf2c5b1f72b0e9719f059d6acde --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_168/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_168/results +Run 1/1 completed in 13.23 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9826664689244784 + public: {'centers_str': ' centers[0] = (0.0938, 0.0979)\n centers[1] = (0.2728, 0.0728)\n centers[2] = (0.5272, 0.0728)\n centers[3] = (0.7062, 0.0979)\n centers[4] = (0.9002, 0.1000)\n centers[5] = (0.0938, 0.3021)\n centers[6] = (0.2728, 0.3272)\n centers[7] = (0.5272, 0.3272)\n centers[8] = (0.7062, 0.3021)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0992, 0.5008)\n centers[11] = (0.2979, 0.5062)\n centers[12] = (0.5021, 0.5062)\n centers[13] = (0.7008, 0.5008)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7002)\n centers[17] = (0.5000, 0.7002)\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.4000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9826664689244784} + visualization_path: + execution_time_mean: 13.227300282102078 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..91669ae2d9c9e0c35442de7b0ceb0193d8fe6806 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9826664689244784, + "public": { + "centers_str": " centers[0] = (0.0938, 0.0979)\n centers[1] = (0.2728, 0.0728)\n centers[2] = (0.5272, 0.0728)\n centers[3] = (0.7062, 0.0979)\n centers[4] = (0.9002, 0.1000)\n centers[5] = (0.0938, 0.3021)\n centers[6] = (0.2728, 0.3272)\n centers[7] = (0.5272, 0.3272)\n centers[8] = (0.7062, 0.3021)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0992, 0.5008)\n centers[11] = (0.2979, 0.5062)\n centers[12] = (0.5021, 0.5062)\n centers[13] = (0.7008, 0.5008)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7002)\n centers[17] = (0.5000, 0.7002)\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.4000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9826664689244784 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_168/results/packing_viz.png", + "execution_time_mean": 13.227300282102078, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d84591ab146bbfd146650f5a4315c3b2f5bf242 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_168/rewrite.txt @@ -0,0 +1,189 @@ +# EVOLVE-BLOCK-START +import numpy as np +from scipy.spatial import Voronoi + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def polygon_centroid(vertices): + """Calculates the centroid of a polygon given its vertices.""" + A = 0.0 + C_x, C_y = 0.0, 0.0 + num_vertices = len(vertices) + if num_vertices == 0: + # Should not happen with valid regions, but return a central point as a fallback + return np.array([0.5, 0.5]) + + for i in range(num_vertices): + x_i, y_i = vertices[i] + x_j, y_j = vertices[(i + 1) % num_vertices] + + cross_product = (x_i * y_j - x_j * y_i) + A += cross_product + C_x += (x_i + x_j) * cross_product + C_y += (y_i + y_j) * cross_product + + if abs(A) < 1e-9: + # Fallback for degenerate polygons (e.g., a line) + return np.mean(vertices, axis=0) + + signed_area = A * 0.5 + C_x /= (6.0 * signed_area) + C_y /= (6.0 * signed_area) + + return np.array([C_x, C_y]) + +def voronoi_relaxation_step(centers, alpha): + """Performs one step of Lloyd's relaxation, moving centers towards their Voronoi centroids.""" + n = centers.shape[0] + + # Create ghost points by reflecting across boundaries to handle bounded Voronoi cells + # This is more robust than manual polygon clipping. + ghost_reflections = [ + centers * np.array([-1, 1]), # x=0 + centers * np.array([1, -1]), # y=0 + centers * np.array([-1, -1]), # corner 0,0 + np.array([2, 1]) - centers * np.array([-1, 1]), # x=1 + np.array([1, 2]) - centers * np.array([1, -1]), # y=1 + np.array([2, 2]) - centers, # corner 1,1 + np.array([0, 2]) - centers * np.array([-1, -1]), # corner 0,1 + np.array([2, 0]) - centers * np.array([-1, -1]) # corner 1,0 + ] + all_points = np.vstack([centers] + ghost_reflections) + + try: + vor = Voronoi(all_points, qhull_options='Qbb Qc Qx') + except Exception: # Catch Qhull errors if points are degenerate + return centers # On failure, return original centers (no move) + + new_centers = np.copy(centers) + for i in range(n): + region_idx = vor.point_region[i] + # Ensure region is valid and bounded + if region_idx == -1 or not vor.regions[region_idx] or -1 in vor.regions[region_idx]: + continue + + region_vertices = vor.vertices[vor.regions[region_idx]] + centroid = polygon_centroid(region_vertices) + + # Move the center towards the centroid by a factor of alpha + direction = centroid - centers[i] + new_centers[i] += alpha * direction + + return new_centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a hybrid of + Voronoi-based Lloyd's Relaxation and Simulated Annealing. + """ + n = 26 + + # 1. Initialization: Asymmetric Gaussian-deformed grid from high-performing ancestors. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + void_center = np.array([0.4, 0.2]) + amplitude, sigma = 0.06, 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + radii = compute_max_radii(centers) + best_centers = centers.copy() + best_radii = radii.copy() + best_sum_radii = np.sum(radii) + + current_centers = centers.copy() + current_radii = radii.copy() + current_sum_radii = best_sum_radii + + # 2. Main Optimization: Hybrid Voronoi-SA Search + total_iterations = 3000 # Fewer iterations as Voronoi steps are more powerful + T_initial, T_final = 0.1, 1e-8 + + # Annealing schedule for Lloyd's relaxation step size + alpha_initial, alpha_final = 0.8, 0.05 + + # Probability of performing a classic stochastic move instead of Voronoi relaxation + stochastic_move_prob = 0.15 + + for it in range(total_iterations): + # Annealing schedules + temp = T_initial * (T_final / T_initial)**(it / total_iterations) + alpha = alpha_initial * (alpha_final / alpha_initial)**(it / total_iterations) + + candidate_centers = current_centers.copy() + + if np.random.rand() < stochastic_move_prob: + # Stochastic Move: Perturb a single circle (helps escape Lloyd's minima) + # Prioritize small circles for this kick + inverse_radii = 1 / (current_radii + 1e-8) + probs = inverse_radii / np.sum(inverse_radii) + circle_idx = np.random.choice(n, p=probs) + + perturb_strength = 0.05 * (1 - it / total_iterations) # Simple annealing perturbation + displacement = np.random.uniform(-perturb_strength, perturb_strength, 2) + candidate_centers[circle_idx] += displacement + + else: + # Voronoi Relaxation Move: Apply one step of Lloyd's algorithm + candidate_centers = voronoi_relaxation_step(current_centers, alpha) + + # Clip all centers to ensure they are within the unit square + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + + # 3. Evaluation and Acceptance + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta = candidate_sum_radii - current_sum_radii + if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + + # Update best solution found so far + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + + return best_centers, best_radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c45c7732d7dba89e69b714b32f859422695f9b50 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..2140af712f721dd5e6e9d4ceeb60db8c568c68f8 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_17/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_17/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9169561144739513 + 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.2000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9169561144739513} + visualization_path: + execution_time_mean: 0.0025586001574993134 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..da1ff150bc99b45b89c7014e9b9bc29a8fb1db46 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9169561144739513, + "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.2000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9169561144739513 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_17/results/packing_viz.png", + "execution_time_mean": 0.0025586001574993134, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3bd0f9612719a9ece316545252da120e7ef8637e Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..301ecd92b5e546624c230e32a8bae83b9eae9f53 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_170/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_170/results +Run 1/1 completed in 34.11 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.3520474943982514 + public: {'centers_str': ' centers[0] = (0.3294, 0.9641)\n centers[1] = (0.3595, 0.6479)\n centers[2] = (0.0988, 0.0979)\n centers[3] = (0.6264, 0.6426)\n centers[4] = (0.6909, 0.2232)\n centers[5] = (0.4363, 0.9061)\n centers[6] = (0.4984, 0.1868)\n centers[7] = (0.0759, 0.9055)\n centers[8] = (0.9107, 0.6449)\n centers[9] = (0.4196, 0.3626)\n centers[10] = (0.1139, 0.7148)\n centers[11] = (0.5502, 0.0694)\n centers[12] = (0.1423, 0.3328)\n centers[13] = (0.6796, 0.0602)\n centers[14] = (0.8876, 0.1036)\n centers[15] = (0.2335, 0.9109)\n centers[16] = (0.2617, 0.5514)\n centers[17] = (0.7243, 0.4614)\n centers[18] = (0.9006, 0.3064)\n centers[19] = (0.7328, 0.6894)\n centers[20] = (0.3210, 0.7539)\n centers[21] = (0.6441, 0.8807)\n centers[22] = (0.8808, 0.8649)\n centers[23] = (0.9298, 0.4837)\n centers[24] = (0.4857, 0.6092)\n centers[25] = (0.3193, 0.1241)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.3520474943982514} + visualization_path: + execution_time_mean: 34.106027893256396 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..b94ddbd1e3f2940fef7724420a7aca0694e02073 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.3520474943982514, + "public": { + "centers_str": " centers[0] = (0.3294, 0.9641)\n centers[1] = (0.3595, 0.6479)\n centers[2] = (0.0988, 0.0979)\n centers[3] = (0.6264, 0.6426)\n centers[4] = (0.6909, 0.2232)\n centers[5] = (0.4363, 0.9061)\n centers[6] = (0.4984, 0.1868)\n centers[7] = (0.0759, 0.9055)\n centers[8] = (0.9107, 0.6449)\n centers[9] = (0.4196, 0.3626)\n centers[10] = (0.1139, 0.7148)\n centers[11] = (0.5502, 0.0694)\n centers[12] = (0.1423, 0.3328)\n centers[13] = (0.6796, 0.0602)\n centers[14] = (0.8876, 0.1036)\n centers[15] = (0.2335, 0.9109)\n centers[16] = (0.2617, 0.5514)\n centers[17] = (0.7243, 0.4614)\n centers[18] = (0.9006, 0.3064)\n centers[19] = (0.7328, 0.6894)\n centers[20] = (0.3210, 0.7539)\n centers[21] = (0.6441, 0.8807)\n centers[22] = (0.8808, 0.8649)\n centers[23] = (0.9298, 0.4837)\n centers[24] = (0.4857, 0.6092)\n centers[25] = (0.3193, 0.1241)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.3520474943982514 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_170/results/packing_viz.png", + "execution_time_mean": 34.106027893256396, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc875e114e77ab1e073b4edb1a6c297143dbc5c7 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..c9c1401bf48f7269411781b921894f7b3a999df6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/edit.diff @@ -0,0 +1,396 @@ +--- a/original.py ++++ b/original.py +@@ -1,248 +1,209 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + +-# compute_max_radii remains unchanged as it's a robust evaluation function. + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) +- + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +-class CirclePacker: +- """ +- Encapsulates the logic for packing circles using a hybrid strategy: +- 1. Multi-start initialization to find a promising starting configuration. +- 2. An advanced Simulated Annealing (SA) search with: +- - Intelligent, context-aware circle selection for perturbation. +- - Adaptive perturbation strength based on circle size. +- - Stagnation detection and escape mechanism. +- 3. Vectorized force-directed relaxation for initial settling and final polishing. ++class CircleOptimizer: ++ """ ++ A hierarchical optimizer for the circle packing problem. It employs a multi-stage ++ strategy including exploration, exploitation, and strategic perturbation to find ++ high-density packings. + """ + def __init__(self, n): + self.n = n +- self.centers = np.zeros((n, 2)) +- +- def _initialize_grid_with_void(self, void_center, amplitude, sigma): +- """Initializes centers from a 5x5 grid deformed by a Gaussian push.""" +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T +- +- displacements = base_centers_25 - void_center +- distances = np.linalg.norm(displacements, axis=1) +- mask = distances > 1e-9 +- +- push_magnitudes = np.zeros(25) +- if np.any(mask): +- push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) +- displacements[mask] /= distances[mask, np.newaxis] +- +- initial_centers = np.zeros((self.n, 2)) +- initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- initial_centers[25] = void_center +- return np.clip(initial_centers, 0.0, 1.0) +- +- def _relax_phase(self, centers_to_relax, iters, step_size, repulsion_strength, +- boundary_strength, repulsion_threshold, boundary_margin): +- """Performs a vectorized force-directed relaxation (jiggle) phase.""" +- for _ in range(iters): +- diff = centers_to_relax[:, np.newaxis, :] - centers_to_relax[np.newaxis, :, :] +- dists = np.linalg.norm(diff, axis=2) +- +- mask = (dists > 1e-9) & (dists < repulsion_threshold) +- +- force_scalar = np.zeros_like(dists) +- # Use inverse-distance force from the original 'jiggle_phase' +- force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] +- +- force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +- forces = np.sum(force_vectors, axis=1) +- +- forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - centers_to_relax[:, 0]) +- forces[:, 0] -= boundary_strength * np.maximum(0, centers_to_relax[:, 0] - (1 - boundary_margin)) +- forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - centers_to_relax[:, 1]) +- forces[:, 1] -= boundary_strength * np.maximum(0, centers_to_relax[:, 1] - (1 - boundary_margin)) +- +- centers_to_relax += step_size * forces +- centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) +- return centers_to_relax +- +- def _select_circle_for_perturbation(self, current_radii, current_centers): +- """Intelligently selects a circle to perturb based on radius, boundary proximity, and crowding.""" +- inverse_radii = 1 / (current_radii + 1e-8) +- +- dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], +- current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) +- boundary_weight = np.exp(-dist_to_boundary / 0.08) +- +- neighbor_counts = np.zeros(self.n) +- for i in range(self.n): +- dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) +- # Count neighbors closer than 1.1 times the sum of radii +- crowd_dist = (current_radii[i] + current_radii) * 1.1 +- neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 # Subtract self +- +- max_neighbors = np.max(neighbor_counts) +- crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) +- +- combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) +- selection_probs = combined_weights / np.sum(combined_weights) +- +- return np.random.choice(self.n, p=selection_probs) +- +- def _adaptive_perturbation(self, base_strength, circle_idx, current_radii): +- """Calculates a larger perturbation for smaller circles.""" +- max_r = np.max(current_radii) + 1e-8 +- relative_radius = current_radii[circle_idx] / max_r +- # Factor is larger for smaller relative_radius +- perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 +- return base_strength * perturb_factor +- +- def pack(self): +- """Executes the full packing process.""" +- +- # --- 1. Multi-Start Initialization --- +- best_initial_sum_radii = -1.0 +- best_initial_centers = None +- +- # Try diverse void centers to find a promising start. +- void_configs = [ +- (np.random.uniform(0.3, 0.7, 2), 0.08), # Random +- (np.array([0.4, 0.2]), 0.06), +- (np.array([0.2, 0.4]), 0.05), +- (np.array([0.6, 0.8]), 0.07), +- (np.array([0.8, 0.6]), 0.065), +- (np.array([0.5, 0.5]), 0.05), ++ self.best_centers = None ++ self.best_score = -1.0 ++ ++ def _update_global_best(self, centers): ++ """Checks if a new configuration is a global best and updates it.""" ++ radii = compute_max_radii(centers) ++ score = np.sum(radii) ++ if score > self.best_score: ++ self.best_score = score ++ self.best_centers = centers.copy() ++ # print(f"New global best: {self.best_score:.5f}") # For debugging ++ return True ++ return False ++ ++ def _generate_initial_configs(self): ++ """Generates a portfolio of diverse starting configurations.""" ++ configs = [] ++ void_params = [ ++ (np.array([0.5, 0.5]), 0.08, 0.15), ++ (np.random.uniform(0.3, 0.7, 2), 0.08, 0.15), ++ (np.array([0.2, 0.2]), 0.06, 0.12), ++ (np.array([0.8, 0.8]), 0.07, 0.12), ++ (np.array([0.3, 0.7]), 0.05, 0.18), + ] +- +- for void_center, amplitude in void_configs: +- candidate_centers = self._initialize_grid_with_void(void_center, amplitude, sigma=0.15) +- +- # Settle the initial configuration with a quick relaxation. +- relaxed_centers = self._relax_phase( +- candidate_centers.copy(), iters=200, step_size=0.002, +- repulsion_strength=0.02, boundary_strength=0.07, +- repulsion_threshold=0.2, boundary_margin=0.04 +- ) +- candidate_radii = compute_max_radii(relaxed_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- if candidate_sum_radii > best_initial_sum_radii: +- best_initial_sum_radii = candidate_sum_radii +- best_initial_centers = relaxed_centers.copy() +- +- # --- 2. Simulated Annealing Main Loop --- +- current_centers = best_initial_centers ++ for center, amp, sig in void_params: ++ x_coords = np.linspace(0.1, 0.9, 5) ++ y_coords = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords, y_coords) ++ base_centers = np.vstack([xx.ravel(), yy.ravel()]).T ++ ++ displacements = base_centers - center ++ distances = np.linalg.norm(displacements, axis=1) ++ push = amp * np.exp(-distances**2 / (2 * sig**2)) ++ ++ # Avoid division by zero ++ safe_distances = distances[:, np.newaxis] ++ safe_distances[safe_distances < 1e-9] = 1.0 ++ ++ pushed_centers = base_centers + (displacements / safe_distances) * push[:, np.newaxis] ++ ++ initial_centers = np.zeros((self.n, 2)) ++ initial_centers[:25] = pushed_centers ++ initial_centers[25] = center ++ configs.append(np.clip(initial_centers, 0, 1)) ++ return configs ++ ++ def _run_annealing_phase(self, initial_centers, iterations, temp_init, temp_final, perturb_init, perturb_final): ++ """A modular simulated annealing process.""" ++ current_centers = initial_centers.copy() + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) +- +- best_centers = current_centers.copy() +- best_sum_radii = current_sum_radii +- +- # SA Parameters +- total_iterations = 20000 +- initial_temp = 0.0008 # High enough for exploration +- final_temp = 1e-9 # Low for greedy refinement +- initial_perturb_strength = 0.035 +- final_perturb_strength = 0.0001 +- +- # Stagnation Escape Parameters +- stagnation_counter = 0 +- stagnation_threshold = 500 # Iterations before a 'kick' +- perturb_boost = 1.0 +- boost_factor = 2.5 +- boost_decay = 0.98 +- +- for iteration in range(total_iterations): +- progress = iteration / total_iterations +- temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) +- base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) +- +- if stagnation_counter >= stagnation_threshold: +- perturb_boost = boost_factor +- stagnation_counter = 0 ++ ++ best_phase_centers = current_centers.copy() ++ best_phase_sum_radii = current_sum_radii ++ ++ for i in range(iterations): ++ progress = i / iterations ++ temp = temp_init * math.exp(math.log(temp_final / temp_init) * progress) ++ base_perturb = perturb_init * math.exp(math.log(perturb_final / perturb_init) * progress) + + candidate_centers = current_centers.copy() + +- circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) +- +- effective_perturb_strength = self._adaptive_perturbation(base_perturb_strength, circle_idx, current_radii) * perturb_boost +- +- displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +- candidate_centers[circle_idx] += displacement +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +- +- # Decay the boost +- if perturb_boost > 1.0: +- perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay +- ++ # Simple but effective adaptive perturbation ++ inv_radii = 1.0 / (current_radii + 1e-8) ++ probs = inv_radii / np.sum(inv_radii) ++ c_idx = np.random.choice(self.n, p=probs) ++ ++ # Perturb smaller circles more ++ max_r = np.max(current_radii) ++ adapt_factor = 1.0 + (1.0 - current_radii[c_idx] / (max_r + 1e-8)) * 1.5 ++ eff_perturb = base_perturb * adapt_factor ++ ++ disp = np.random.uniform(-eff_perturb, eff_perturb, 2) ++ candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + disp, 0.0, 1.0) ++ + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii +- if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): ++ if delta_E > 0 or np.random.rand() < math.exp(delta_E / temp): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii +- +- if current_sum_radii > best_sum_radii: +- best_sum_radii = current_sum_radii +- best_centers = current_centers.copy() +- stagnation_counter = 0 +- else: +- stagnation_counter += 1 +- else: +- stagnation_counter += 1 +- +- # --- 3. Final Gentle Polish --- +- final_centers = self._relax_phase( +- best_centers, iters=300, step_size=0.0001, repulsion_strength=0.001, +- boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 +- ) +- final_radii = compute_max_radii(final_centers) +- +- return final_centers, final_radii ++ if current_sum_radii > best_phase_sum_radii: ++ best_phase_sum_radii = current_sum_radii ++ best_phase_centers = current_centers.copy() ++ ++ return best_phase_centers ++ ++ def _apply_structural_kick(self, centers): ++ """Swaps a small and a large circle to escape deep local minima.""" ++ kicked_centers = centers.copy() ++ radii = compute_max_radii(kicked_centers) ++ ++ sorted_indices = np.argsort(radii) ++ ++ # Pick one of the 3 smallest and one of the 3 largest ++ idx_small = np.random.choice(sorted_indices[:3]) ++ idx_large = np.random.choice(sorted_indices[-3:]) ++ ++ # Swap their positions ++ kicked_centers[idx_small], kicked_centers[idx_large] = \ ++ kicked_centers[idx_large].copy(), kicked_centers[idx_small].copy() ++ ++ return kicked_centers ++ ++ def _relax(self, centers, iters, step, rep_str, bnd_str, rep_thr, bnd_mar): ++ """A final polishing step.""" ++ for _ in range(iters): ++ diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] ++ dists = np.linalg.norm(diff, axis=2) ++ mask = (dists > 1e-9) & (dists < rep_thr) ++ force_scalar = np.zeros_like(dists) ++ force_scalar[mask] = rep_str * (rep_thr - dists[mask]) / dists[mask] ++ force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ forces = np.sum(force_vectors, axis=1) ++ forces[:, 0] += bnd_str * np.maximum(0, bnd_mar - centers[:, 0]) - bnd_str * np.maximum(0, centers[:, 0] - (1 - bnd_mar)) ++ forces[:, 1] += bnd_str * np.maximum(0, bnd_mar - centers[:, 1]) - bnd_str * np.maximum(0, centers[:, 1] - (1 - bnd_mar)) ++ centers = np.clip(centers + step * forces, 0.0, 1.0) ++ return centers ++ ++ def pack(self): ++ """Executes the full hierarchical optimization pipeline.""" ++ # --- Stage 1: Exploration --- ++ initial_configs = self._generate_initial_configs() ++ for config in initial_configs: ++ # Settle first ++ settled_config = self._relax(config, 100, 0.002, 0.02, 0.07, 0.2, 0.04) ++ # Short, aggressive annealing ++ optimized_centers = self._run_annealing_phase(settled_config, 4000, 0.001, 1e-8, 0.05, 0.001) ++ self._update_global_best(optimized_centers) ++ ++ # --- Stage 2: Exploitation --- ++ # Long, fine-grained annealing on the best candidate so far ++ exploited_centers = self._run_annealing_phase(self.best_centers, 12000, 0.0008, 1e-9, 0.035, 0.0001) ++ self._update_global_best(exploited_centers) ++ ++ # --- Stage 3: Strategic Perturbation (The "Kick") --- ++ kicked_centers = self._apply_structural_kick(self.best_centers) ++ ++ # --- Stage 4: Re-optimization & Polish --- ++ # Re-anneal from the kicked state ++ reoptimized_centers = self._run_annealing_phase(kicked_centers, 6000, 0.0008, 1e-9, 0.03, 0.0005) ++ self._update_global_best(reoptimized_centers) ++ ++ # Final polish on the all-time best configuration ++ final_centers = self._relax(self.best_centers, 300, 0.0001, 0.001, 0.005, 0.18, 0.02) ++ self._update_global_best(final_centers) ++ ++ return self.best_centers, compute_max_radii(self.best_centers) + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and +- running the advanced CirclePacker class. ++ running the hierarchical CircleOptimizer. + """ + n = 26 +- packer = CirclePacker(n) +- centers, radii = packer.pack() ++ optimizer = CircleOptimizer(n) ++ centers, radii = optimizer.pack() + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/main.py new file mode 100644 index 0000000000000000000000000000000000000000..b44f45f5736d76cee41d0db8cb20a324780879a0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/main.py @@ -0,0 +1,209 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CircleOptimizer: + """ + A hierarchical optimizer for the circle packing problem. It employs a multi-stage + strategy including exploration, exploitation, and strategic perturbation to find + high-density packings. + """ + def __init__(self, n): + self.n = n + self.best_centers = None + self.best_score = -1.0 + + def _update_global_best(self, centers): + """Checks if a new configuration is a global best and updates it.""" + radii = compute_max_radii(centers) + score = np.sum(radii) + if score > self.best_score: + self.best_score = score + self.best_centers = centers.copy() + # print(f"New global best: {self.best_score:.5f}") # For debugging + return True + return False + + def _generate_initial_configs(self): + """Generates a portfolio of diverse starting configurations.""" + configs = [] + void_params = [ + (np.array([0.5, 0.5]), 0.08, 0.15), + (np.random.uniform(0.3, 0.7, 2), 0.08, 0.15), + (np.array([0.2, 0.2]), 0.06, 0.12), + (np.array([0.8, 0.8]), 0.07, 0.12), + (np.array([0.3, 0.7]), 0.05, 0.18), + ] + for center, amp, sig in void_params: + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers - center + distances = np.linalg.norm(displacements, axis=1) + push = amp * np.exp(-distances**2 / (2 * sig**2)) + + # Avoid division by zero + safe_distances = distances[:, np.newaxis] + safe_distances[safe_distances < 1e-9] = 1.0 + + pushed_centers = base_centers + (displacements / safe_distances) * push[:, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = pushed_centers + initial_centers[25] = center + configs.append(np.clip(initial_centers, 0, 1)) + return configs + + def _run_annealing_phase(self, initial_centers, iterations, temp_init, temp_final, perturb_init, perturb_final): + """A modular simulated annealing process.""" + current_centers = initial_centers.copy() + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_phase_centers = current_centers.copy() + best_phase_sum_radii = current_sum_radii + + for i in range(iterations): + progress = i / iterations + temp = temp_init * math.exp(math.log(temp_final / temp_init) * progress) + base_perturb = perturb_init * math.exp(math.log(perturb_final / perturb_init) * progress) + + candidate_centers = current_centers.copy() + + # Simple but effective adaptive perturbation + inv_radii = 1.0 / (current_radii + 1e-8) + probs = inv_radii / np.sum(inv_radii) + c_idx = np.random.choice(self.n, p=probs) + + # Perturb smaller circles more + max_r = np.max(current_radii) + adapt_factor = 1.0 + (1.0 - current_radii[c_idx] / (max_r + 1e-8)) * 1.5 + eff_perturb = base_perturb * adapt_factor + + disp = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + disp, 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or np.random.rand() < math.exp(delta_E / temp): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + if current_sum_radii > best_phase_sum_radii: + best_phase_sum_radii = current_sum_radii + best_phase_centers = current_centers.copy() + + return best_phase_centers + + def _apply_structural_kick(self, centers): + """Swaps a small and a large circle to escape deep local minima.""" + kicked_centers = centers.copy() + radii = compute_max_radii(kicked_centers) + + sorted_indices = np.argsort(radii) + + # Pick one of the 3 smallest and one of the 3 largest + idx_small = np.random.choice(sorted_indices[:3]) + idx_large = np.random.choice(sorted_indices[-3:]) + + # Swap their positions + kicked_centers[idx_small], kicked_centers[idx_large] = \ + kicked_centers[idx_large].copy(), kicked_centers[idx_small].copy() + + return kicked_centers + + def _relax(self, centers, iters, step, rep_str, bnd_str, rep_thr, bnd_mar): + """A final polishing step.""" + for _ in range(iters): + diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + mask = (dists > 1e-9) & (dists < rep_thr) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = rep_str * (rep_thr - dists[mask]) / dists[mask] + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + forces[:, 0] += bnd_str * np.maximum(0, bnd_mar - centers[:, 0]) - bnd_str * np.maximum(0, centers[:, 0] - (1 - bnd_mar)) + forces[:, 1] += bnd_str * np.maximum(0, bnd_mar - centers[:, 1]) - bnd_str * np.maximum(0, centers[:, 1] - (1 - bnd_mar)) + centers = np.clip(centers + step * forces, 0.0, 1.0) + return centers + + def pack(self): + """Executes the full hierarchical optimization pipeline.""" + # --- Stage 1: Exploration --- + initial_configs = self._generate_initial_configs() + for config in initial_configs: + # Settle first + settled_config = self._relax(config, 100, 0.002, 0.02, 0.07, 0.2, 0.04) + # Short, aggressive annealing + optimized_centers = self._run_annealing_phase(settled_config, 4000, 0.001, 1e-8, 0.05, 0.001) + self._update_global_best(optimized_centers) + + # --- Stage 2: Exploitation --- + # Long, fine-grained annealing on the best candidate so far + exploited_centers = self._run_annealing_phase(self.best_centers, 12000, 0.0008, 1e-9, 0.035, 0.0001) + self._update_global_best(exploited_centers) + + # --- Stage 3: Strategic Perturbation (The "Kick") --- + kicked_centers = self._apply_structural_kick(self.best_centers) + + # --- Stage 4: Re-optimization & Polish --- + # Re-anneal from the kicked state + reoptimized_centers = self._run_annealing_phase(kicked_centers, 6000, 0.0008, 1e-9, 0.03, 0.0005) + self._update_global_best(reoptimized_centers) + + # Final polish on the all-time best configuration + final_centers = self._relax(self.best_centers, 300, 0.0001, 0.001, 0.005, 0.18, 0.02) + self._update_global_best(final_centers) + + return self.best_centers, compute_max_radii(self.best_centers) + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the hierarchical CircleOptimizer. + """ + n = 26 + optimizer = CircleOptimizer(n) + centers, radii = optimizer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/original.py new file mode 100644 index 0000000000000000000000000000000000000000..b0a3ca5704864051e77a9ac097b2718478e9eb5d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/original.py @@ -0,0 +1,248 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + Encapsulates the logic for packing circles using a hybrid strategy: + 1. Multi-start initialization to find a promising starting configuration. + 2. An advanced Simulated Annealing (SA) search with: + - Intelligent, context-aware circle selection for perturbation. + - Adaptive perturbation strength based on circle size. + - Stagnation detection and escape mechanism. + 3. Vectorized force-directed relaxation for initial settling and final polishing. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + + def _initialize_grid_with_void(self, void_center, amplitude, sigma): + """Initializes centers from a 5x5 grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + def _relax_phase(self, centers_to_relax, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation (jiggle) phase.""" + for _ in range(iters): + diff = centers_to_relax[:, np.newaxis, :] - centers_to_relax[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + # Use inverse-distance force from the original 'jiggle_phase' + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - centers_to_relax[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, centers_to_relax[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - centers_to_relax[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, centers_to_relax[:, 1] - (1 - boundary_margin)) + + centers_to_relax += step_size * forces + centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) + return centers_to_relax + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """Intelligently selects a circle to perturb based on radius, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(self.n) + for i in range(self.n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + # Count neighbors closer than 1.1 times the sum of radii + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 # Subtract self + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + + return np.random.choice(self.n, p=selection_probs) + + def _adaptive_perturbation(self, base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + # Factor is larger for smaller relative_radius + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + + def pack(self): + """Executes the full packing process.""" + + # --- 1. Multi-Start Initialization --- + best_initial_sum_radii = -1.0 + best_initial_centers = None + + # Try diverse void centers to find a promising start. + void_configs = [ + (np.random.uniform(0.3, 0.7, 2), 0.08), # Random + (np.array([0.4, 0.2]), 0.06), + (np.array([0.2, 0.4]), 0.05), + (np.array([0.6, 0.8]), 0.07), + (np.array([0.8, 0.6]), 0.065), + (np.array([0.5, 0.5]), 0.05), + ] + + for void_center, amplitude in void_configs: + candidate_centers = self._initialize_grid_with_void(void_center, amplitude, sigma=0.15) + + # Settle the initial configuration with a quick relaxation. + relaxed_centers = self._relax_phase( + candidate_centers.copy(), iters=200, step_size=0.002, + repulsion_strength=0.02, boundary_strength=0.07, + repulsion_threshold=0.2, boundary_margin=0.04 + ) + candidate_radii = compute_max_radii(relaxed_centers) + candidate_sum_radii = np.sum(candidate_radii) + + if candidate_sum_radii > best_initial_sum_radii: + best_initial_sum_radii = candidate_sum_radii + best_initial_centers = relaxed_centers.copy() + + # --- 2. Simulated Annealing Main Loop --- + current_centers = best_initial_centers + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_sum_radii = current_sum_radii + + # SA Parameters + total_iterations = 20000 + initial_temp = 0.0008 # High enough for exploration + final_temp = 1e-9 # Low for greedy refinement + initial_perturb_strength = 0.035 + final_perturb_strength = 0.0001 + + # Stagnation Escape Parameters + stagnation_counter = 0 + stagnation_threshold = 500 # Iterations before a 'kick' + perturb_boost = 1.0 + boost_factor = 2.5 + boost_decay = 0.98 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + + effective_perturb_strength = self._adaptive_perturbation(base_perturb_strength, circle_idx, current_radii) * perturb_boost + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the boost + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + # --- 3. Final Gentle Polish --- + final_centers = self._relax_phase( + best_centers, iters=300, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 + ) + final_radii = compute_max_radii(final_centers) + + return final_centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the advanced CirclePacker class. + """ + n = 26 + packer = CirclePacker(n) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..98aeabee980907d04f990743c562e57436299071 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_171/main.py:153: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..c9b0069c7f431aca6aa4518ab30954b3c5fafc78 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_171/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_171/results +Run 1/1 completed in 79.46 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.244124857983398 + public: {'centers_str': ' centers[0] = (0.0668, 0.0669)\n centers[1] = (0.3715, 0.0788)\n centers[2] = (0.5116, 0.0620)\n centers[3] = (0.7751, 0.4305)\n centers[4] = (0.8993, 0.1007)\n centers[5] = (0.0611, 0.3101)\n centers[6] = (0.4386, 0.2530)\n centers[7] = (0.5420, 0.6900)\n centers[8] = (0.6902, 0.2693)\n centers[9] = (0.9014, 0.3000)\n centers[10] = (0.1138, 0.4781)\n centers[11] = (0.3496, 0.4376)\n centers[12] = (0.5301, 0.5403)\n centers[13] = (0.6422, 0.0827)\n centers[14] = (0.8975, 0.5009)\n centers[15] = (0.1058, 0.6972)\n centers[16] = (0.3438, 0.6733)\n centers[17] = (0.5167, 0.7458)\n centers[18] = (0.6804, 0.6736)\n centers[19] = (0.9018, 0.7015)\n centers[20] = (0.0997, 0.9013)\n centers[21] = (0.2972, 0.9009)\n centers[22] = (0.4969, 0.8991)\n centers[23] = (0.6989, 0.8989)\n centers[24] = (0.9000, 0.8997)\n centers[25] = (0.2222, 0.1930)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.244124857983398} + visualization_path: + execution_time_mean: 79.45867619011551 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..d6a2c96f6ffa2db2d8a85ad4d68c3a38e57fdbfd --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.244124857983398, + "public": { + "centers_str": " centers[0] = (0.0668, 0.0669)\n centers[1] = (0.3715, 0.0788)\n centers[2] = (0.5116, 0.0620)\n centers[3] = (0.7751, 0.4305)\n centers[4] = (0.8993, 0.1007)\n centers[5] = (0.0611, 0.3101)\n centers[6] = (0.4386, 0.2530)\n centers[7] = (0.5420, 0.6900)\n centers[8] = (0.6902, 0.2693)\n centers[9] = (0.9014, 0.3000)\n centers[10] = (0.1138, 0.4781)\n centers[11] = (0.3496, 0.4376)\n centers[12] = (0.5301, 0.5403)\n centers[13] = (0.6422, 0.0827)\n centers[14] = (0.8975, 0.5009)\n centers[15] = (0.1058, 0.6972)\n centers[16] = (0.3438, 0.6733)\n centers[17] = (0.5167, 0.7458)\n centers[18] = (0.6804, 0.6736)\n centers[19] = (0.9018, 0.7015)\n centers[20] = (0.0997, 0.9013)\n centers[21] = (0.2972, 0.9009)\n centers[22] = (0.4969, 0.8991)\n centers[23] = (0.6989, 0.8989)\n centers[24] = (0.9000, 0.8997)\n centers[25] = (0.2222, 0.1930)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.244124857983398 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_171/results/packing_viz.png", + "execution_time_mean": 79.45867619011551, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9daeb4b5d49d66d1861fee7e0ada87235d6f6b4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_171/rewrite.txt @@ -0,0 +1,200 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CircleOptimizer: + """ + A hierarchical optimizer for the circle packing problem. It employs a multi-stage + strategy including exploration, exploitation, and strategic perturbation to find + high-density packings. + """ + def __init__(self, n): + self.n = n + self.best_centers = None + self.best_score = -1.0 + + def _update_global_best(self, centers): + """Checks if a new configuration is a global best and updates it.""" + radii = compute_max_radii(centers) + score = np.sum(radii) + if score > self.best_score: + self.best_score = score + self.best_centers = centers.copy() + # print(f"New global best: {self.best_score:.5f}") # For debugging + return True + return False + + def _generate_initial_configs(self): + """Generates a portfolio of diverse starting configurations.""" + configs = [] + void_params = [ + (np.array([0.5, 0.5]), 0.08, 0.15), + (np.random.uniform(0.3, 0.7, 2), 0.08, 0.15), + (np.array([0.2, 0.2]), 0.06, 0.12), + (np.array([0.8, 0.8]), 0.07, 0.12), + (np.array([0.3, 0.7]), 0.05, 0.18), + ] + for center, amp, sig in void_params: + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers - center + distances = np.linalg.norm(displacements, axis=1) + push = amp * np.exp(-distances**2 / (2 * sig**2)) + + # Avoid division by zero + safe_distances = distances[:, np.newaxis] + safe_distances[safe_distances < 1e-9] = 1.0 + + pushed_centers = base_centers + (displacements / safe_distances) * push[:, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = pushed_centers + initial_centers[25] = center + configs.append(np.clip(initial_centers, 0, 1)) + return configs + + def _run_annealing_phase(self, initial_centers, iterations, temp_init, temp_final, perturb_init, perturb_final): + """A modular simulated annealing process.""" + current_centers = initial_centers.copy() + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_phase_centers = current_centers.copy() + best_phase_sum_radii = current_sum_radii + + for i in range(iterations): + progress = i / iterations + temp = temp_init * math.exp(math.log(temp_final / temp_init) * progress) + base_perturb = perturb_init * math.exp(math.log(perturb_final / perturb_init) * progress) + + candidate_centers = current_centers.copy() + + # Simple but effective adaptive perturbation + inv_radii = 1.0 / (current_radii + 1e-8) + probs = inv_radii / np.sum(inv_radii) + c_idx = np.random.choice(self.n, p=probs) + + # Perturb smaller circles more + max_r = np.max(current_radii) + adapt_factor = 1.0 + (1.0 - current_radii[c_idx] / (max_r + 1e-8)) * 1.5 + eff_perturb = base_perturb * adapt_factor + + disp = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + disp, 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or np.random.rand() < math.exp(delta_E / temp): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + if current_sum_radii > best_phase_sum_radii: + best_phase_sum_radii = current_sum_radii + best_phase_centers = current_centers.copy() + + return best_phase_centers + + def _apply_structural_kick(self, centers): + """Swaps a small and a large circle to escape deep local minima.""" + kicked_centers = centers.copy() + radii = compute_max_radii(kicked_centers) + + sorted_indices = np.argsort(radii) + + # Pick one of the 3 smallest and one of the 3 largest + idx_small = np.random.choice(sorted_indices[:3]) + idx_large = np.random.choice(sorted_indices[-3:]) + + # Swap their positions + kicked_centers[idx_small], kicked_centers[idx_large] = \ + kicked_centers[idx_large].copy(), kicked_centers[idx_small].copy() + + return kicked_centers + + def _relax(self, centers, iters, step, rep_str, bnd_str, rep_thr, bnd_mar): + """A final polishing step.""" + for _ in range(iters): + diff = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + mask = (dists > 1e-9) & (dists < rep_thr) + force_scalar = np.zeros_like(dists) + force_scalar[mask] = rep_str * (rep_thr - dists[mask]) / dists[mask] + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + forces[:, 0] += bnd_str * np.maximum(0, bnd_mar - centers[:, 0]) - bnd_str * np.maximum(0, centers[:, 0] - (1 - bnd_mar)) + forces[:, 1] += bnd_str * np.maximum(0, bnd_mar - centers[:, 1]) - bnd_str * np.maximum(0, centers[:, 1] - (1 - bnd_mar)) + centers = np.clip(centers + step * forces, 0.0, 1.0) + return centers + + def pack(self): + """Executes the full hierarchical optimization pipeline.""" + # --- Stage 1: Exploration --- + initial_configs = self._generate_initial_configs() + for config in initial_configs: + # Settle first + settled_config = self._relax(config, 100, 0.002, 0.02, 0.07, 0.2, 0.04) + # Short, aggressive annealing + optimized_centers = self._run_annealing_phase(settled_config, 4000, 0.001, 1e-8, 0.05, 0.001) + self._update_global_best(optimized_centers) + + # --- Stage 2: Exploitation --- + # Long, fine-grained annealing on the best candidate so far + exploited_centers = self._run_annealing_phase(self.best_centers, 12000, 0.0008, 1e-9, 0.035, 0.0001) + self._update_global_best(exploited_centers) + + # --- Stage 3: Strategic Perturbation (The "Kick") --- + kicked_centers = self._apply_structural_kick(self.best_centers) + + # --- Stage 4: Re-optimization & Polish --- + # Re-anneal from the kicked state + reoptimized_centers = self._run_annealing_phase(kicked_centers, 6000, 0.0008, 1e-9, 0.03, 0.0005) + self._update_global_best(reoptimized_centers) + + # Final polish on the all-time best configuration + final_centers = self._relax(self.best_centers, 300, 0.0001, 0.001, 0.005, 0.18, 0.02) + self._update_global_best(final_centers) + + return self.best_centers, compute_max_radii(self.best_centers) + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the hierarchical CircleOptimizer. + """ + n = 26 + optimizer = CircleOptimizer(n) + centers, radii = optimizer.pack() + return centers, radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ea2f9f25c77dccadb4c568428879961e13bde58 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..be616a86cafe2d0be1fcd730d7186f5df3f5e4d6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_174/main.py:74: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..bd96672f5913ef53fbbb967da517f4db441cc84a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_174/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_174/results +Run 1/1 completed in 311.73 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.410021116837768 + public: {'centers_str': ' centers[0] = (0.5363, 0.6369)\n centers[1] = (0.7306, 0.8926)\n centers[2] = (0.3215, 0.3897)\n centers[3] = (0.7236, 0.0889)\n centers[4] = (0.0808, 0.3045)\n centers[5] = (0.7396, 0.5336)\n centers[6] = (0.7236, 0.3689)\n centers[7] = (0.5481, 0.8938)\n centers[8] = (0.6776, 0.7100)\n centers[9] = (0.3312, 0.0939)\n centers[10] = (0.5349, 0.2233)\n centers[11] = (0.0977, 0.4791)\n centers[12] = (0.3227, 0.8821)\n centers[13] = (0.8988, 0.6989)\n centers[14] = (0.2945, 0.5596)\n centers[15] = (0.5533, 0.5004)\n centers[16] = (0.2604, 0.2785)\n centers[17] = (0.9000, 0.9001)\n centers[18] = (0.9007, 0.2992)\n centers[19] = (0.1096, 0.6860)\n centers[20] = (0.1031, 0.8978)\n centers[21] = (0.1150, 0.1150)\n centers[22] = (0.8998, 0.1000)\n centers[23] = (0.4559, 0.7056)\n centers[24] = (0.9004, 0.4981)\n centers[25] = (0.3959, 0.3889)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.410021116837768} + visualization_path: + execution_time_mean: 311.73273070389405 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..732c6f079783fd09b7574026f2584689a347c19d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.410021116837768, + "public": { + "centers_str": " centers[0] = (0.5363, 0.6369)\n centers[1] = (0.7306, 0.8926)\n centers[2] = (0.3215, 0.3897)\n centers[3] = (0.7236, 0.0889)\n centers[4] = (0.0808, 0.3045)\n centers[5] = (0.7396, 0.5336)\n centers[6] = (0.7236, 0.3689)\n centers[7] = (0.5481, 0.8938)\n centers[8] = (0.6776, 0.7100)\n centers[9] = (0.3312, 0.0939)\n centers[10] = (0.5349, 0.2233)\n centers[11] = (0.0977, 0.4791)\n centers[12] = (0.3227, 0.8821)\n centers[13] = (0.8988, 0.6989)\n centers[14] = (0.2945, 0.5596)\n centers[15] = (0.5533, 0.5004)\n centers[16] = (0.2604, 0.2785)\n centers[17] = (0.9000, 0.9001)\n centers[18] = (0.9007, 0.2992)\n centers[19] = (0.1096, 0.6860)\n centers[20] = (0.1031, 0.8978)\n centers[21] = (0.1150, 0.1150)\n centers[22] = (0.8998, 0.1000)\n centers[23] = (0.4559, 0.7056)\n centers[24] = (0.9004, 0.4981)\n centers[25] = (0.3959, 0.3889)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.410021116837768 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_174/results/packing_viz.png", + "execution_time_mean": 311.73273070389405, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..216b5d627460917418131b1097b8129198358376 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..bc6b53de6bb85ebe34c2c029e7602025a07c2571 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/edit.diff @@ -0,0 +1,359 @@ +--- a/original.py ++++ b/original.py +@@ -1,248 +1,208 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + + def _generate_void_config(n, void_center, amplitude, sigma): + """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + def relaxation_stage(centers, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation (jiggle) phase.""" + relaxed_centers = centers.copy() + for _ in range(iters): + diff = relaxed_centers[:, np.newaxis, :] - relaxed_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, relaxed_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, relaxed_centers[:, 1] - (1 - boundary_margin)) + + relaxed_centers += step_size * forces + relaxed_centers = np.clip(relaxed_centers, 0.0, 1.0) + return relaxed_centers + +-def _select_circle_context_aware(n, current_radii, current_centers): +- """Intelligently selects a circle to perturb based on radius, boundary proximity, and crowding.""" +- inverse_radii = 1 / (current_radii + 1e-8) +- +- dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) +- boundary_weight = np.exp(-dist_to_boundary / 0.08) +- +- neighbor_counts = np.zeros(n) +- for i in range(n): +- dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) +- crowd_dist = (current_radii[i] + current_radii) * 1.1 +- neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 +- +- max_neighbors = np.max(neighbor_counts) +- crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(n) +- +- combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) +- selection_probs = combined_weights / np.sum(combined_weights) +- return np.random.choice(n, p=selection_probs) +- +-def _adaptive_perturbation_strength(base_strength, circle_idx, current_radii): +- """Calculates a larger perturbation for smaller circles.""" +- max_r = np.max(current_radii) + 1e-8 +- relative_radius = current_radii[circle_idx] / max_r +- perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 +- return base_strength * perturb_factor +- +-def annealing_stage(centers, n): +- """Performs the main simulated annealing optimization stage.""" +- current_centers = centers.copy() +- current_radii = compute_max_radii(current_centers) +- current_sum_radii = np.sum(current_radii) +- +- best_centers = current_centers.copy() +- best_sum_radii = current_sum_radii +- +- # SA Parameters +- total_iterations = 20000 +- initial_temp = 0.0008 +- final_temp = 1e-9 +- initial_perturb_strength = 0.035 +- final_perturb_strength = 0.0001 +- +- # Stagnation Escape Parameters +- stagnation_counter = 0 +- stagnation_threshold = 800 +- perturb_boost = 1.0 +- boost_factor = 3.0 +- boost_decay = 0.98 +- +- for iteration in range(total_iterations): +- progress = iteration / total_iterations +- +- # Annealing schedules +- temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) +- base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) +- +- # Stagnation escape: boost perturbation and reheat temperature +- if stagnation_counter >= stagnation_threshold: +- perturb_boost = boost_factor +- temp = temp_schedule + initial_temp * 0.4 # Reheat +- stagnation_counter = 0 +- else: +- temp = temp_schedule +- +- candidate_centers = current_centers.copy() +- +- circle_idx = _select_circle_context_aware(n, current_radii, current_centers) +- +- effective_perturb_strength = _adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost +- +- displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +- candidate_centers[circle_idx] += displacement +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +- +- if perturb_boost > 1.0: +- perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay +- +- candidate_radii = compute_max_radii(candidate_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- delta_E = candidate_sum_radii - current_sum_radii +- if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): +- current_centers = candidate_centers +- current_radii = candidate_radii +- current_sum_radii = candidate_sum_radii +- +- if current_sum_radii > best_sum_radii: +- best_sum_radii = current_sum_radii +- best_centers = current_centers.copy() +- stagnation_counter = 0 +- else: +- stagnation_counter += 1 +- else: +- stagnation_counter += 1 +- +- return best_centers +- +-def initialization_stage(n): +- """Performs a multi-start initialization and selects the best starting point.""" +- best_initial_sum_radii = -1.0 +- best_initial_centers = None +- +- # Diverse void configurations to try +- void_configs = [ +- (np.array([0.4, 0.2]), 0.06), +- (np.array([0.2, 0.4]), 0.05), +- (np.array([0.6, 0.8]), 0.07), +- (np.array([0.8, 0.6]), 0.065), +- (np.array([0.5, 0.5]), 0.05), +- (np.random.uniform(0.3, 0.7, 2), 0.08), +- ] +- +- for void_center, amplitude in void_configs: +- candidate_centers = _generate_void_config(n, void_center, amplitude, sigma=0.15) +- +- # Settle with a very quick relaxation +- relaxed_centers = relaxation_stage( +- candidate_centers, iters=150, step_size=0.002, +- repulsion_strength=0.02, boundary_strength=0.07, +- repulsion_threshold=0.2, boundary_margin=0.04 +- ) +- candidate_radii = compute_max_radii(relaxed_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- if candidate_sum_radii > best_initial_sum_radii: +- best_initial_sum_radii = candidate_sum_radii +- best_initial_centers = relaxed_centers.copy() +- +- return best_initial_centers ++ ++class ParticleSwarmOptimizer: ++ def __init__(self, n, num_particles, max_iter): ++ self.n = n ++ self.dim = n * 2 ++ self.num_particles = num_particles ++ self.max_iter = max_iter ++ ++ # PSO parameters ++ self.w_range = (0.9, 0.4) # Inertia weight range ++ self.c1 = 1.5 # Cognitive coefficient ++ self.c2 = 1.5 # Social coefficient ++ self.v_max = 0.2 # Max velocity change per step ++ ++ # Initialize swarm ++ self.positions = np.zeros((self.num_particles, self.dim)) ++ self.velocities = np.random.uniform(-0.01, 0.01, (self.num_particles, self.dim)) ++ ++ self.pbest_positions = np.zeros_like(self.positions) ++ self.pbest_scores = np.full(self.num_particles, -1.0) ++ ++ self.gbest_position = np.zeros(self.dim) ++ self.gbest_score = -1.0 ++ ++ def _initialize_swarm(self): ++ """Creates a diverse initial population of particles.""" ++ for i in range(self.num_particles): ++ # Generate diverse starting points using randomized void configurations ++ void_center = np.random.uniform(0.25, 0.75, 2) ++ amplitude = np.random.uniform(0.05, 0.12) ++ sigma = np.random.uniform(0.1, 0.2) ++ ++ initial_centers = _generate_void_config(self.n, void_center, amplitude, sigma) ++ relaxed_centers = relaxation_stage(initial_centers, 50, 0.002, 0.01, 0.05, 0.2, 0.05) ++ ++ self.positions[i] = relaxed_centers.flatten() ++ self.pbest_positions[i] = self.positions[i].copy() ++ ++ # Initial evaluation ++ radii = compute_max_radii(relaxed_centers) ++ score = np.sum(radii) ++ self.pbest_scores[i] = score ++ ++ if score > self.gbest_score: ++ self.gbest_score = score ++ self.gbest_position = self.positions[i].copy() ++ ++ def optimize(self): ++ """Runs the main PSO loop.""" ++ self._initialize_swarm() ++ ++ for i in range(self.max_iter): ++ # Anneal inertia weight ++ w = self.w_range[0] - (self.w_range[0] - self.w_range[1]) * (i / self.max_iter) ++ ++ for p_idx in range(self.num_particles): ++ # Evaluate current particle's position ++ current_centers = self.positions[p_idx].reshape(self.n, 2) ++ current_radii = compute_max_radii(current_centers) ++ current_score = np.sum(current_radii) ++ ++ # Update personal best (pbest) ++ if current_score > self.pbest_scores[p_idx]: ++ self.pbest_scores[p_idx] = current_score ++ self.pbest_positions[p_idx] = self.positions[p_idx].copy() ++ ++ # Update global best (gbest) ++ if current_score > self.gbest_score: ++ self.gbest_score = current_score ++ self.gbest_position = self.positions[p_idx].copy() ++ ++ # Update velocities and positions for all particles ++ r1 = np.random.rand(self.num_particles, self.dim) ++ r2 = np.random.rand(self.num_particles, self.dim) ++ ++ cognitive_velocity = self.c1 * r1 * (self.pbest_positions - self.positions) ++ social_velocity = self.c2 * r2 * (self.gbest_position - self.positions) ++ ++ self.velocities = w * self.velocities + cognitive_velocity + social_velocity ++ ++ # Clamp velocity ++ self.velocities = np.clip(self.velocities, -self.v_max, self.v_max) ++ ++ # Update positions ++ self.positions += self.velocities ++ ++ # Clamp positions to the unit square [0, 1] ++ self.positions = np.clip(self.positions, 0.0, 1.0) ++ ++ return self.gbest_position.reshape(self.n, 2) + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles using a functional, +- multi-stage optimization pipeline. ++ Constructs a high-density arrangement of 26 circles using Particle Swarm Optimization. + """ + n = 26 + +- # Stage 1: Multi-Start Initialization to find a robust starting point +- initial_centers = initialization_stage(n) ++ # 1. PSO Main Optimization Stage ++ pso = ParticleSwarmOptimizer(n=n, num_particles=40, max_iter=500) ++ best_centers_pso = pso.optimize() + +- # Stage 2: Main Simulated Annealing optimization +- # The initial relaxation is now part of the initialization stage, +- # so we can directly proceed to annealing. +- annealed_centers = annealing_stage(initial_centers, n) +- +- # Stage 3: Final gentle polish using relaxation ++ # 2. Final Polishing Stage ++ # Apply a gentle relaxation to the best solution found by PSO to fine-tune it. + final_centers = relaxation_stage( +- annealed_centers, iters=300, step_size=0.0001, +- repulsion_strength=0.001, boundary_strength=0.005, +- repulsion_threshold=0.18, boundary_margin=0.02 ++ best_centers_pso, ++ iters=300, ++ step_size=0.0001, ++ repulsion_strength=0.001, ++ boundary_strength=0.005, ++ repulsion_threshold=0.18, ++ boundary_margin=0.02 + ) + + # Final evaluation + final_radii = compute_max_radii(final_centers) +- annealed_radii = compute_max_radii(annealed_centers) +- +- # Return the best result between the SA output and the polished version +- if np.sum(final_radii) > np.sum(annealed_radii): ++ pso_radii = compute_max_radii(best_centers_pso) ++ ++ # Return the best result between the raw PSO output and the polished version ++ if np.sum(final_radii) > np.sum(pso_radii): + return final_centers, final_radii + else: +- return annealed_centers, annealed_radii ++ return best_centers_pso, pso_radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/main.py new file mode 100644 index 0000000000000000000000000000000000000000..67ac4d13dbf649b31202ed2ca79b255d12c92c1f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/main.py @@ -0,0 +1,208 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +def _generate_void_config(n, void_center, amplitude, sigma): + """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + +def relaxation_stage(centers, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation (jiggle) phase.""" + relaxed_centers = centers.copy() + for _ in range(iters): + diff = relaxed_centers[:, np.newaxis, :] - relaxed_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, relaxed_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, relaxed_centers[:, 1] - (1 - boundary_margin)) + + relaxed_centers += step_size * forces + relaxed_centers = np.clip(relaxed_centers, 0.0, 1.0) + return relaxed_centers + + +class ParticleSwarmOptimizer: + def __init__(self, n, num_particles, max_iter): + self.n = n + self.dim = n * 2 + self.num_particles = num_particles + self.max_iter = max_iter + + # PSO parameters + self.w_range = (0.9, 0.4) # Inertia weight range + self.c1 = 1.5 # Cognitive coefficient + self.c2 = 1.5 # Social coefficient + self.v_max = 0.2 # Max velocity change per step + + # Initialize swarm + self.positions = np.zeros((self.num_particles, self.dim)) + self.velocities = np.random.uniform(-0.01, 0.01, (self.num_particles, self.dim)) + + self.pbest_positions = np.zeros_like(self.positions) + self.pbest_scores = np.full(self.num_particles, -1.0) + + self.gbest_position = np.zeros(self.dim) + self.gbest_score = -1.0 + + def _initialize_swarm(self): + """Creates a diverse initial population of particles.""" + for i in range(self.num_particles): + # Generate diverse starting points using randomized void configurations + void_center = np.random.uniform(0.25, 0.75, 2) + amplitude = np.random.uniform(0.05, 0.12) + sigma = np.random.uniform(0.1, 0.2) + + initial_centers = _generate_void_config(self.n, void_center, amplitude, sigma) + relaxed_centers = relaxation_stage(initial_centers, 50, 0.002, 0.01, 0.05, 0.2, 0.05) + + self.positions[i] = relaxed_centers.flatten() + self.pbest_positions[i] = self.positions[i].copy() + + # Initial evaluation + radii = compute_max_radii(relaxed_centers) + score = np.sum(radii) + self.pbest_scores[i] = score + + if score > self.gbest_score: + self.gbest_score = score + self.gbest_position = self.positions[i].copy() + + def optimize(self): + """Runs the main PSO loop.""" + self._initialize_swarm() + + for i in range(self.max_iter): + # Anneal inertia weight + w = self.w_range[0] - (self.w_range[0] - self.w_range[1]) * (i / self.max_iter) + + for p_idx in range(self.num_particles): + # Evaluate current particle's position + current_centers = self.positions[p_idx].reshape(self.n, 2) + current_radii = compute_max_radii(current_centers) + current_score = np.sum(current_radii) + + # Update personal best (pbest) + if current_score > self.pbest_scores[p_idx]: + self.pbest_scores[p_idx] = current_score + self.pbest_positions[p_idx] = self.positions[p_idx].copy() + + # Update global best (gbest) + if current_score > self.gbest_score: + self.gbest_score = current_score + self.gbest_position = self.positions[p_idx].copy() + + # Update velocities and positions for all particles + r1 = np.random.rand(self.num_particles, self.dim) + r2 = np.random.rand(self.num_particles, self.dim) + + cognitive_velocity = self.c1 * r1 * (self.pbest_positions - self.positions) + social_velocity = self.c2 * r2 * (self.gbest_position - self.positions) + + self.velocities = w * self.velocities + cognitive_velocity + social_velocity + + # Clamp velocity + self.velocities = np.clip(self.velocities, -self.v_max, self.v_max) + + # Update positions + self.positions += self.velocities + + # Clamp positions to the unit square [0, 1] + self.positions = np.clip(self.positions, 0.0, 1.0) + + return self.gbest_position.reshape(self.n, 2) + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using Particle Swarm Optimization. + """ + n = 26 + + # 1. PSO Main Optimization Stage + pso = ParticleSwarmOptimizer(n=n, num_particles=40, max_iter=500) + best_centers_pso = pso.optimize() + + # 2. Final Polishing Stage + # Apply a gentle relaxation to the best solution found by PSO to fine-tune it. + final_centers = relaxation_stage( + best_centers_pso, + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Final evaluation + final_radii = compute_max_radii(final_centers) + pso_radii = compute_max_radii(best_centers_pso) + + # Return the best result between the raw PSO output and the polished version + if np.sum(final_radii) > np.sum(pso_radii): + return final_centers, final_radii + else: + return best_centers_pso, pso_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/original.py new file mode 100644 index 0000000000000000000000000000000000000000..421f394661b30ee7d16c20af349163083a3772f3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/original.py @@ -0,0 +1,248 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +def _generate_void_config(n, void_center, amplitude, sigma): + """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + +def relaxation_stage(centers, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation (jiggle) phase.""" + relaxed_centers = centers.copy() + for _ in range(iters): + diff = relaxed_centers[:, np.newaxis, :] - relaxed_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, relaxed_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, relaxed_centers[:, 1] - (1 - boundary_margin)) + + relaxed_centers += step_size * forces + relaxed_centers = np.clip(relaxed_centers, 0.0, 1.0) + return relaxed_centers + +def _select_circle_context_aware(n, current_radii, current_centers): + """Intelligently selects a circle to perturb based on radius, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(n) + for i in range(n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(n, p=selection_probs) + +def _adaptive_perturbation_strength(base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + +def annealing_stage(centers, n): + """Performs the main simulated annealing optimization stage.""" + current_centers = centers.copy() + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_sum_radii = current_sum_radii + + # SA Parameters + total_iterations = 20000 + initial_temp = 0.0008 + final_temp = 1e-9 + initial_perturb_strength = 0.035 + final_perturb_strength = 0.0001 + + # Stagnation Escape Parameters + stagnation_counter = 0 + stagnation_threshold = 800 + perturb_boost = 1.0 + boost_factor = 3.0 + boost_decay = 0.98 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + + # Annealing schedules + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Stagnation escape: boost perturbation and reheat temperature + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + temp = temp_schedule + initial_temp * 0.4 # Reheat + stagnation_counter = 0 + else: + temp = temp_schedule + + candidate_centers = current_centers.copy() + + circle_idx = _select_circle_context_aware(n, current_radii, current_centers) + + effective_perturb_strength = _adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + return best_centers + +def initialization_stage(n): + """Performs a multi-start initialization and selects the best starting point.""" + best_initial_sum_radii = -1.0 + best_initial_centers = None + + # Diverse void configurations to try + void_configs = [ + (np.array([0.4, 0.2]), 0.06), + (np.array([0.2, 0.4]), 0.05), + (np.array([0.6, 0.8]), 0.07), + (np.array([0.8, 0.6]), 0.065), + (np.array([0.5, 0.5]), 0.05), + (np.random.uniform(0.3, 0.7, 2), 0.08), + ] + + for void_center, amplitude in void_configs: + candidate_centers = _generate_void_config(n, void_center, amplitude, sigma=0.15) + + # Settle with a very quick relaxation + relaxed_centers = relaxation_stage( + candidate_centers, iters=150, step_size=0.002, + repulsion_strength=0.02, boundary_strength=0.07, + repulsion_threshold=0.2, boundary_margin=0.04 + ) + candidate_radii = compute_max_radii(relaxed_centers) + candidate_sum_radii = np.sum(candidate_radii) + + if candidate_sum_radii > best_initial_sum_radii: + best_initial_sum_radii = candidate_sum_radii + best_initial_centers = relaxed_centers.copy() + + return best_initial_centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a functional, + multi-stage optimization pipeline. + """ + n = 26 + + # Stage 1: Multi-Start Initialization to find a robust starting point + initial_centers = initialization_stage(n) + + # Stage 2: Main Simulated Annealing optimization + # The initial relaxation is now part of the initialization stage, + # so we can directly proceed to annealing. + annealed_centers = annealing_stage(initial_centers, n) + + # Stage 3: Final gentle polish using relaxation + final_centers = relaxation_stage( + annealed_centers, iters=300, step_size=0.0001, + repulsion_strength=0.001, boundary_strength=0.005, + repulsion_threshold=0.18, boundary_margin=0.02 + ) + + # Final evaluation + final_radii = compute_max_radii(final_centers) + annealed_radii = compute_max_radii(annealed_centers) + + # Return the best result between the SA output and the polished version + if np.sum(final_radii) > np.sum(annealed_radii): + return final_centers, final_radii + else: + return annealed_centers, annealed_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..9e32c4bebe04c77e042cd9c1a6df87845b066f8b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_175/main.py:65: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..82dda6b7b6f1f9c85f717c31dddd6b5c61a6f983 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_175/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_175/results +Run 1/1 completed in 42.03 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.0970037963324546 + public: {'centers_str': ' centers[0] = (0.0984, 0.0984)\n centers[1] = (0.2856, 0.0891)\n centers[2] = (0.5012, 0.0976)\n centers[3] = (0.7006, 0.0993)\n centers[4] = (0.8981, 0.0983)\n centers[5] = (0.0918, 0.2886)\n centers[6] = (0.3084, 0.2694)\n centers[7] = (0.5403, 0.2379)\n centers[8] = (0.7097, 0.2746)\n centers[9] = (0.9015, 0.2950)\n centers[10] = (0.0849, 0.4652)\n centers[11] = (0.2427, 0.5610)\n centers[12] = (0.6110, 0.6291)\n centers[13] = (0.7262, 0.5107)\n centers[14] = (0.8967, 0.4971)\n centers[15] = (0.0936, 0.7084)\n centers[16] = (0.2997, 0.7044)\n centers[17] = (0.5226, 0.7161)\n centers[18] = (0.7123, 0.6795)\n centers[19] = (0.9066, 0.6963)\n centers[20] = (0.0995, 0.9010)\n centers[21] = (0.3078, 0.9055)\n centers[22] = (0.4987, 0.9031)\n centers[23] = (0.6954, 0.9002)\n centers[24] = (0.8976, 0.8926)\n centers[25] = (0.4436, 0.4610)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.0970037963324546} + visualization_path: + execution_time_mean: 42.02926907502115 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..02d59222df507e939c5bed994fcd4cd1964e9955 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.0970037963324546, + "public": { + "centers_str": " centers[0] = (0.0984, 0.0984)\n centers[1] = (0.2856, 0.0891)\n centers[2] = (0.5012, 0.0976)\n centers[3] = (0.7006, 0.0993)\n centers[4] = (0.8981, 0.0983)\n centers[5] = (0.0918, 0.2886)\n centers[6] = (0.3084, 0.2694)\n centers[7] = (0.5403, 0.2379)\n centers[8] = (0.7097, 0.2746)\n centers[9] = (0.9015, 0.2950)\n centers[10] = (0.0849, 0.4652)\n centers[11] = (0.2427, 0.5610)\n centers[12] = (0.6110, 0.6291)\n centers[13] = (0.7262, 0.5107)\n centers[14] = (0.8967, 0.4971)\n centers[15] = (0.0936, 0.7084)\n centers[16] = (0.2997, 0.7044)\n centers[17] = (0.5226, 0.7161)\n centers[18] = (0.7123, 0.6795)\n centers[19] = (0.9066, 0.6963)\n centers[20] = (0.0995, 0.9010)\n centers[21] = (0.3078, 0.9055)\n centers[22] = (0.4987, 0.9031)\n centers[23] = (0.6954, 0.9002)\n centers[24] = (0.8976, 0.8926)\n centers[25] = (0.4436, 0.4610)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.0970037963324546 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_175/results/packing_viz.png", + "execution_time_mean": 42.02926907502115, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..03fdeccddc80a292c4c55a99f1431ebfdb3e81d9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_175/rewrite.txt @@ -0,0 +1,199 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +def _generate_void_config(n, void_center, amplitude, sigma): + """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + +def relaxation_stage(centers, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation (jiggle) phase.""" + relaxed_centers = centers.copy() + for _ in range(iters): + diff = relaxed_centers[:, np.newaxis, :] - relaxed_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, relaxed_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, relaxed_centers[:, 1] - (1 - boundary_margin)) + + relaxed_centers += step_size * forces + relaxed_centers = np.clip(relaxed_centers, 0.0, 1.0) + return relaxed_centers + + +class ParticleSwarmOptimizer: + def __init__(self, n, num_particles, max_iter): + self.n = n + self.dim = n * 2 + self.num_particles = num_particles + self.max_iter = max_iter + + # PSO parameters + self.w_range = (0.9, 0.4) # Inertia weight range + self.c1 = 1.5 # Cognitive coefficient + self.c2 = 1.5 # Social coefficient + self.v_max = 0.2 # Max velocity change per step + + # Initialize swarm + self.positions = np.zeros((self.num_particles, self.dim)) + self.velocities = np.random.uniform(-0.01, 0.01, (self.num_particles, self.dim)) + + self.pbest_positions = np.zeros_like(self.positions) + self.pbest_scores = np.full(self.num_particles, -1.0) + + self.gbest_position = np.zeros(self.dim) + self.gbest_score = -1.0 + + def _initialize_swarm(self): + """Creates a diverse initial population of particles.""" + for i in range(self.num_particles): + # Generate diverse starting points using randomized void configurations + void_center = np.random.uniform(0.25, 0.75, 2) + amplitude = np.random.uniform(0.05, 0.12) + sigma = np.random.uniform(0.1, 0.2) + + initial_centers = _generate_void_config(self.n, void_center, amplitude, sigma) + relaxed_centers = relaxation_stage(initial_centers, 50, 0.002, 0.01, 0.05, 0.2, 0.05) + + self.positions[i] = relaxed_centers.flatten() + self.pbest_positions[i] = self.positions[i].copy() + + # Initial evaluation + radii = compute_max_radii(relaxed_centers) + score = np.sum(radii) + self.pbest_scores[i] = score + + if score > self.gbest_score: + self.gbest_score = score + self.gbest_position = self.positions[i].copy() + + def optimize(self): + """Runs the main PSO loop.""" + self._initialize_swarm() + + for i in range(self.max_iter): + # Anneal inertia weight + w = self.w_range[0] - (self.w_range[0] - self.w_range[1]) * (i / self.max_iter) + + for p_idx in range(self.num_particles): + # Evaluate current particle's position + current_centers = self.positions[p_idx].reshape(self.n, 2) + current_radii = compute_max_radii(current_centers) + current_score = np.sum(current_radii) + + # Update personal best (pbest) + if current_score > self.pbest_scores[p_idx]: + self.pbest_scores[p_idx] = current_score + self.pbest_positions[p_idx] = self.positions[p_idx].copy() + + # Update global best (gbest) + if current_score > self.gbest_score: + self.gbest_score = current_score + self.gbest_position = self.positions[p_idx].copy() + + # Update velocities and positions for all particles + r1 = np.random.rand(self.num_particles, self.dim) + r2 = np.random.rand(self.num_particles, self.dim) + + cognitive_velocity = self.c1 * r1 * (self.pbest_positions - self.positions) + social_velocity = self.c2 * r2 * (self.gbest_position - self.positions) + + self.velocities = w * self.velocities + cognitive_velocity + social_velocity + + # Clamp velocity + self.velocities = np.clip(self.velocities, -self.v_max, self.v_max) + + # Update positions + self.positions += self.velocities + + # Clamp positions to the unit square [0, 1] + self.positions = np.clip(self.positions, 0.0, 1.0) + + return self.gbest_position.reshape(self.n, 2) + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using Particle Swarm Optimization. + """ + n = 26 + + # 1. PSO Main Optimization Stage + pso = ParticleSwarmOptimizer(n=n, num_particles=40, max_iter=500) + best_centers_pso = pso.optimize() + + # 2. Final Polishing Stage + # Apply a gentle relaxation to the best solution found by PSO to fine-tune it. + final_centers = relaxation_stage( + best_centers_pso, + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Final evaluation + final_radii = compute_max_radii(final_centers) + pso_radii = compute_max_radii(best_centers_pso) + + # Return the best result between the raw PSO output and the polished version + if np.sum(final_radii) > np.sum(pso_radii): + return final_centers, final_radii + else: + return best_centers_pso, pso_radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0eb5f3099c139e850e2a048e87d8c299a45db0e Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..275432fa7893d2f4f6e069e2e3bc93163c9256bf --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/edit.diff @@ -0,0 +1,572 @@ +--- a/original.py ++++ b/original.py +@@ -1,248 +1,366 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + +-def compute_max_radii(centers): ++def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. ++ ++ Args: ++ centers: np.array of shape (n, 2) with (x, y) coordinates ++ max_iterations: Maximum iterations for convergence. ++ ++ Returns: ++ np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] ++ ++ # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + +- for _ in range(500): ++ for _ in range(max_iterations): # Use dynamic max_iterations + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True ++ else: # If both radii are already ~0, ensure they are exactly 0 ++ radii[i] = 0.0 ++ radii[j] = 0.0 ++ changes_made = True + if not changes_made: + break + return radii + +-def _generate_void_config(n, void_center, amplitude, sigma): +- """Helper to generate initial centers from a grid deformed by a Gaussian push.""" +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T +- +- displacements = base_centers_25 - void_center +- distances = np.linalg.norm(displacements, axis=1) +- mask = distances > 1e-9 +- +- push_magnitudes = np.zeros(25) +- if np.any(mask): +- push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) +- displacements[mask] /= distances[mask, np.newaxis] +- +- initial_centers = np.zeros((n, 2)) +- initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- initial_centers[25] = void_center +- return np.clip(initial_centers, 0.0, 1.0) +- +-def relaxation_stage(centers, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): +- """Performs a vectorized force-directed relaxation (jiggle) phase.""" +- relaxed_centers = centers.copy() +- for _ in range(iters): +- diff = relaxed_centers[:, np.newaxis, :] - relaxed_centers[np.newaxis, :, :] +- dists = np.linalg.norm(diff, axis=2) +- +- mask = (dists > 1e-9) & (dists < repulsion_threshold) ++class CirclePacker: ++ """ ++ A class to encapsulate the state and logic for packing circles using ++ a hybrid approach: initial aggressive perturbation, a quick force-directed ++ relaxation, and then a primary optimization via simulated annealing. ++ ++ This structure aims to combine the benefits of force-directed methods ++ (quick stabilization) with metaheuristics (escaping local optima). ++ """ ++ ++ def __init__(self, n=26): ++ """Initializes the packer with the number of circles.""" ++ self.n = n ++ self.centers = np.zeros((n, 2)) ++ ++ def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): ++ """ ++ Generates an initial configuration by creating a base 5x5 grid, ++ aggressively deforming it to create a void, and placing the 26th circle. ++ The deformation helps break the initial grid symmetry. ++ """ ++ # Start with a 5x5 grid for the first 25 circles. ++ x_coords = np.linspace(0.1, 0.9, 5) ++ y_coords = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords, y_coords) ++ base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T ++ ++ # Vectorized Gaussian push to create the void. ++ displacements = base_centers_25 - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center ++ ++ push_magnitudes = np.zeros(25) ++ # Apply push only to points not exactly at the void center ++ if np.any(mask): ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ ++ # Normalize displacement vectors and apply the push ++ displacements[mask] /= distances[mask, np.newaxis] ++ ++ initial_centers = np.zeros((self.n, 2)) ++ initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ initial_centers[25] = void_center # The 26th circle goes into the void ++ self.centers = np.clip(initial_centers, 0.0, 1.0) ++ ++ def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, ++ boundary_strength, repulsion_threshold, boundary_margin): ++ """ ++ Applies a force-directed relaxation step using vectorized calculations. ++ This helps quickly resolve immediate overlaps and stabilize the configuration. ++ """ ++ for _ in range(iters): ++ forces = np.zeros_like(self.centers) ++ ++ # Vectorized Circle-Circle Repulsion ++ diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] # (N, N, 2) ++ dists = np.linalg.norm(diff, axis=2) # (N, N) ++ ++ # Mask out self-interaction by setting diagonal distances to a very large value ++ np.fill_diagonal(dists, np.inf) ++ ++ # Repulsion mask for pairs that are close enough to interact ++ repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) ++ ++ # Compute force magnitudes for interacting pairs ++ force_magnitudes = np.zeros_like(dists) ++ force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] ++ ++ # Compute force vectors F_ij (force on i from j) ++ # F_ij direction is (centers[i] - centers[j]) / dists[i,j] ++ # Store unit vectors: normalized_diff[i,j] = (centers[i] - centers[j]) / dists[i,j] ++ normalized_diff = np.zeros_like(diff) ++ # Avoid division by zero where dists might be zero or inf (already handled diag to inf) ++ normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ ++ # Sum force_magnitudes[i,j] * normalized_diff[i,j] over j for each i ++ # This correctly sums F_ij (force exerted by j on i) for all j!=i ++ forces_repulsion = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) ++ forces += forces_repulsion ++ ++ # Vectorized Boundary Repulsion ++ forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) ++ forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) ++ forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) ++ forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) ++ ++ self.centers += step_size * forces ++ self.centers = np.clip(self.centers, 0.0, 1.0) ++ ++ ++ def _select_circle_context_aware(self, current_radii, current_centers): ++ """Intelligently selects a circle to perturb based on inverse radius, boundary proximity, and crowding.""" ++ inverse_radii = 1 / (current_radii + 1e-8) ++ ++ dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], ++ current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) ++ boundary_weight = np.exp(-dist_to_boundary / 0.08) # Circles near boundary get higher weight ++ ++ neighbor_counts = np.zeros(self.n) ++ for i in range(self.n): ++ dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) ++ crowd_dist = (current_radii[i] + current_radii) * 1.1 # Check for neighbors closer than 1.1 * sum of radii ++ neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 # Subtract self ++ ++ max_neighbors = np.max(neighbor_counts) ++ crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) ++ ++ # Combine weights: smaller radius, closer to boundary, more crowded -> higher probability of selection ++ combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) ++ selection_probs = combined_weights / np.sum(combined_weights) + +- force_scalar = np.zeros_like(dists) +- force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] +- +- force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +- forces = np.sum(force_vectors, axis=1) +- +- forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 0]) +- forces[:, 0] -= boundary_strength * np.maximum(0, relaxed_centers[:, 0] - (1 - boundary_margin)) +- forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 1]) +- forces[:, 1] -= boundary_strength * np.maximum(0, relaxed_centers[:, 1] - (1 - boundary_margin)) +- +- relaxed_centers += step_size * forces +- relaxed_centers = np.clip(relaxed_centers, 0.0, 1.0) +- return relaxed_centers +- +-def _select_circle_context_aware(n, current_radii, current_centers): +- """Intelligently selects a circle to perturb based on radius, boundary proximity, and crowding.""" +- inverse_radii = 1 / (current_radii + 1e-8) +- +- dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) +- boundary_weight = np.exp(-dist_to_boundary / 0.08) +- +- neighbor_counts = np.zeros(n) +- for i in range(n): +- dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) +- crowd_dist = (current_radii[i] + current_radii) * 1.1 +- neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 +- +- max_neighbors = np.max(neighbor_counts) +- crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(n) +- +- combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) +- selection_probs = combined_weights / np.sum(combined_weights) +- return np.random.choice(n, p=selection_probs) +- +-def _adaptive_perturbation_strength(base_strength, circle_idx, current_radii): +- """Calculates a larger perturbation for smaller circles.""" +- max_r = np.max(current_radii) + 1e-8 +- relative_radius = current_radii[circle_idx] / max_r +- perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 +- return base_strength * perturb_factor +- +-def annealing_stage(centers, n): +- """Performs the main simulated annealing optimization stage.""" +- current_centers = centers.copy() +- current_radii = compute_max_radii(current_centers) +- current_sum_radii = np.sum(current_radii) +- +- best_centers = current_centers.copy() +- best_sum_radii = current_sum_radii +- +- # SA Parameters +- total_iterations = 20000 +- initial_temp = 0.0008 +- final_temp = 1e-9 +- initial_perturb_strength = 0.035 +- final_perturb_strength = 0.0001 +- +- # Stagnation Escape Parameters +- stagnation_counter = 0 +- stagnation_threshold = 800 +- perturb_boost = 1.0 +- boost_factor = 3.0 +- boost_decay = 0.98 +- +- for iteration in range(total_iterations): +- progress = iteration / total_iterations +- +- # Annealing schedules +- temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) +- base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) +- +- # Stagnation escape: boost perturbation and reheat temperature +- if stagnation_counter >= stagnation_threshold: +- perturb_boost = boost_factor +- temp = temp_schedule + initial_temp * 0.4 # Reheat +- stagnation_counter = 0 +- else: +- temp = temp_schedule +- +- candidate_centers = current_centers.copy() +- +- circle_idx = _select_circle_context_aware(n, current_radii, current_centers) +- +- effective_perturb_strength = _adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost +- +- displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +- candidate_centers[circle_idx] += displacement +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +- +- if perturb_boost > 1.0: +- perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay +- +- candidate_radii = compute_max_radii(candidate_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- delta_E = candidate_sum_radii - current_sum_radii +- if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): +- current_centers = candidate_centers +- current_radii = candidate_radii +- current_sum_radii = candidate_sum_radii +- +- if current_sum_radii > best_sum_radii: +- best_sum_radii = current_sum_radii +- best_centers = current_centers.copy() +- stagnation_counter = 0 ++ return np.random.choice(self.n, p=selection_probs) ++ ++ def _adaptive_perturbation_strength(self, base_strength, circle_idx, current_radii): ++ """Calculates a larger perturbation for smaller circles, allowing them to move more freely.""" ++ max_r = np.max(current_radii) + 1e-8 ++ relative_radius = current_radii[circle_idx] / max_r ++ # Factor is larger for smaller relative_radius ++ perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 ++ return base_strength * perturb_factor ++ ++ def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, ++ initial_perturb_strength, final_perturb_strength): ++ """ ++ Performs a simulated annealing optimization on the circle centers. ++ It incorporates multi-modal perturbations and adaptive `compute_max_radii` iterations. ++ """ ++ best_centers = self.centers.copy() ++ best_radii = compute_max_radii(best_centers) ++ best_sum_radii = np.sum(best_radii) ++ ++ current_centers = best_centers.copy() ++ current_radii = best_radii.copy() ++ current_sum_radii = best_sum_radii ++ ++ # Perturbation strategy probabilities ++ swap_perturb_prob = 0.15 # Probability of performing a small-large circle swap ++ cluster_perturb_prob = 0.1 # Probability of performing a clustered perturbation ++ single_perturb_prob = 1.0 - swap_perturb_prob - cluster_perturb_prob # Remainder for single circle move ++ ++ # Stagnation detection and escape parameters ++ stagnation_counter = 0 ++ stagnation_threshold = 1200 # Iterations without finding a new best to trigger a boost ++ perturb_boost = 1.0 ++ boost_factor = 3.5 # Stronger kick ++ boost_decay = 0.96 # Slightly faster decay ++ temp_reheat_factor_on_stagnation = 0.6 # More significant reheating ++ ++ # Adaptive compute_max_radii iterations ++ min_radii_iters = 100 ++ max_radii_iters = 750 ++ ++ for iteration in range(total_iterations): ++ progress = iteration / total_iterations ++ # Logarithmic decay for temperature and perturbation strength ++ temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) ++ base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) ++ ++ # Adaptive `compute_max_radii` iterations: fewer early, more later ++ radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) ++ ++ current_temp = temp_schedule # Use the scheduled temperature by default ++ ++ # Check for stagnation and apply a temporary perturbation boost and temperature reheat ++ if stagnation_counter >= stagnation_threshold: ++ perturb_boost = boost_factor ++ current_temp = temp_schedule + initial_temp * temp_reheat_factor_on_stagnation # Reheat temperature ++ stagnation_counter = 0 # Reset counter after triggering boost ++ ++ candidate_centers = current_centers.copy() ++ rand_val = np.random.rand() ++ ++ if rand_val < swap_perturb_prob: ++ # Type 1: Swap Perturbation (reintroduced) ++ sorted_indices = np.argsort(current_radii) ++ if self.n > 1: ++ num_small_candidates = max(1, self.n // 4) # Consider top 25% smallest ++ num_large_candidates = max(1, self.n // 4) # Consider top 25% largest ++ ++ small_circles_indices = sorted_indices[:num_small_candidates] ++ large_circles_indices = sorted_indices[-num_large_candidates:] ++ ++ if len(small_circles_indices) > 0 and len(large_circles_indices) > 0: ++ idx_small = np.random.choice(small_circles_indices) ++ idx_large = np.random.choice(large_circles_indices) ++ ++ # Swap positions ++ candidate_centers[idx_small], candidate_centers[idx_large] = \ ++ candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() ++ elif rand_val < swap_perturb_prob + cluster_perturb_prob: ++ # Type 2: Clustered Perturbation (new) ++ # Select a primary circle using context-aware selection ++ primary_idx = self._select_circle_context_aware(current_radii, current_centers) ++ ++ # Find its 2 closest neighbors (excluding self) ++ distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) ++ # Ensure the primary circle itself is not considered a neighbor (distance is 0) ++ distances_to_primary[primary_idx] = np.inf ++ neighbor_indices = np.argsort(distances_to_primary)[:2] # Get 2 closest neighbors ++ ++ # Collect all indices to perturb: primary + neighbors ++ indices_to_perturb = [primary_idx] ++ indices_to_perturb.extend(neighbor_indices) ++ ++ # Calculate effective perturbation for the cluster (scaled down) ++ effective_perturb_strength = self._adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost ++ cluster_move_strength = effective_perturb_strength * 0.7 # Cluster moves are generally smaller ++ ++ displacement = np.random.uniform(-cluster_move_strength, cluster_move_strength, 2) ++ ++ # Apply the displacement to all circles in the cluster ++ for idx in indices_to_perturb: ++ candidate_centers[idx] += displacement ++ candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: +- stagnation_counter += 1 +- else: +- stagnation_counter += 1 +- +- return best_centers +- +-def initialization_stage(n): +- """Performs a multi-start initialization and selects the best starting point.""" +- best_initial_sum_radii = -1.0 +- best_initial_centers = None +- +- # Diverse void configurations to try +- void_configs = [ +- (np.array([0.4, 0.2]), 0.06), +- (np.array([0.2, 0.4]), 0.05), +- (np.array([0.6, 0.8]), 0.07), +- (np.array([0.8, 0.6]), 0.065), +- (np.array([0.5, 0.5]), 0.05), +- (np.random.uniform(0.3, 0.7, 2), 0.08), +- ] +- +- for void_center, amplitude in void_configs: +- candidate_centers = _generate_void_config(n, void_center, amplitude, sigma=0.15) +- +- # Settle with a very quick relaxation +- relaxed_centers = relaxation_stage( +- candidate_centers, iters=150, step_size=0.002, +- repulsion_strength=0.02, boundary_strength=0.07, +- repulsion_threshold=0.2, boundary_margin=0.04 ++ # Type 3: Single Circle Displacement (existing) ++ circle_idx = self._select_circle_context_aware(current_radii, current_centers) ++ effective_perturb_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost ++ ++ displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) ++ ++ # Decay the perturbation boost so its effect is temporary ++ if perturb_boost > 1.0: ++ perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay ++ ++ # Evaluate the new configuration with adaptive radii iterations ++ candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) ++ candidate_sum_radii = np.sum(candidate_radii) ++ ++ # Metropolis-Hastings acceptance criterion ++ delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better ++ if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): ++ # Accept the new state ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers ++ current_radii = candidate_radii ++ ++ # If this is the best state found so far, save it ++ if current_sum_radii > best_sum_radii: ++ best_sum_radii = current_sum_radii ++ best_centers = current_centers.copy() ++ best_radii = current_radii.copy() ++ stagnation_counter = 0 # Reset on new best ++ else: ++ stagnation_counter += 1 # Accepted a state, but it wasn't the best ++ else: ++ stagnation_counter += 1 # Rejected a state ++ ++ self.centers = best_centers # Update the class's centers to the best found ++ return best_radii # Return best radii for convenience ++ ++ def pack(self): ++ """ ++ Orchestrates the entire packing process: ++ 1. Aggressive initial placement with a central void. ++ 2. A short, vectorized force-directed relaxation to quickly stabilize. ++ 3. A primary optimization phase using simulated annealing local search. ++ 4. A final gentle force-directed relaxation for polish. ++ """ ++ # 1. Aggressive initial placement with a *randomized* void center ++ random_void_center = np.random.uniform(0.3, 0.7, 2) ++ self._initial_placement_with_void_and_perturbation( ++ void_center=random_void_center, ++ amplitude=0.08, ++ sigma=0.15 + ) +- candidate_radii = compute_max_radii(relaxed_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- if candidate_sum_radii > best_initial_sum_radii: +- best_initial_sum_radii = candidate_sum_radii +- best_initial_centers = relaxed_centers.copy() +- +- return best_initial_centers ++ ++ # 2. Short, aggressive force-directed relaxation to resolve immediate chaos ++ self._force_directed_relaxation_vectorized( ++ iters=500, # More iterations for initial cleanup ++ step_size=0.002, ++ repulsion_strength=0.02, ++ boundary_strength=0.08, ++ repulsion_threshold=0.19, ++ boundary_margin=0.04 ++ ) ++ ++ # 3. Simulated Annealing Local Search for global optimization ++ self._simulated_annealing_search( ++ total_iterations=35000, # Increased iterations for more thorough search ++ initial_temp=0.0008, # Slightly adjusted initial temp ++ final_temp=1e-10, # Slightly lower final temp ++ initial_perturb_strength=0.035, # Slightly adjusted initial perturbation ++ final_perturb_strength=0.0001 ++ ) ++ ++ # 4. After SA, apply one final gentle relaxation to ensure local stability ++ # and resolve any tiny remaining overlaps or improve boundary contact. ++ self._force_directed_relaxation_vectorized( ++ iters=300, ++ step_size=0.0001, ++ repulsion_strength=0.001, ++ boundary_strength=0.005, ++ repulsion_threshold=0.18, ++ boundary_margin=0.02 ++ ) ++ ++ # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. ++ final_radii = compute_max_radii(self.centers) ++ ++ return self.centers, final_radii ++ + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles using a functional, +- multi-stage optimization pipeline. +- """ +- n = 26 +- +- # Stage 1: Multi-Start Initialization to find a robust starting point +- initial_centers = initialization_stage(n) +- +- # Stage 2: Main Simulated Annealing optimization +- # The initial relaxation is now part of the initialization stage, +- # so we can directly proceed to annealing. +- annealed_centers = annealing_stage(initial_centers, n) +- +- # Stage 3: Final gentle polish using relaxation +- final_centers = relaxation_stage( +- annealed_centers, iters=300, step_size=0.0001, +- repulsion_strength=0.001, boundary_strength=0.005, +- repulsion_threshold=0.18, boundary_margin=0.02 +- ) +- +- # Final evaluation +- final_radii = compute_max_radii(final_centers) +- annealed_radii = compute_max_radii(annealed_centers) +- +- # Return the best result between the SA output and the polished version +- if np.sum(final_radii) > np.sum(annealed_radii): +- return final_centers, final_radii +- else: +- return annealed_centers, annealed_radii ++ Constructs a high-density arrangement of 26 circles using the CirclePacker class. ++ """ ++ packer = CirclePacker(n=26) ++ centers, radii = packer.pack() ++ return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/main.py new file mode 100644 index 0000000000000000000000000000000000000000..f942a109b0899fcbd9847f48d65059656b7b2727 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/main.py @@ -0,0 +1,366 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: Maximum iterations for convergence. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): # Use dynamic max_iterations + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] # (N, N, 2) + dists = np.linalg.norm(diff, axis=2) # (N, N) + + # Mask out self-interaction by setting diagonal distances to a very large value + np.fill_diagonal(dists, np.inf) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors F_ij (force on i from j) + # F_ij direction is (centers[i] - centers[j]) / dists[i,j] + # Store unit vectors: normalized_diff[i,j] = (centers[i] - centers[j]) / dists[i,j] + normalized_diff = np.zeros_like(diff) + # Avoid division by zero where dists might be zero or inf (already handled diag to inf) + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # Sum force_magnitudes[i,j] * normalized_diff[i,j] over j for each i + # This correctly sums F_ij (force exerted by j on i) for all j!=i + forces_repulsion = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + forces += forces_repulsion + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _select_circle_context_aware(self, current_radii, current_centers): + """Intelligently selects a circle to perturb based on inverse radius, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) # Circles near boundary get higher weight + + neighbor_counts = np.zeros(self.n) + for i in range(self.n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 # Check for neighbors closer than 1.1 * sum of radii + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 # Subtract self + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) + + # Combine weights: smaller radius, closer to boundary, more crowded -> higher probability of selection + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + + return np.random.choice(self.n, p=selection_probs) + + def _adaptive_perturbation_strength(self, base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles, allowing them to move more freely.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + # Factor is larger for smaller relative_radius + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It incorporates multi-modal perturbations and adaptive `compute_max_radii` iterations. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Perturbation strategy probabilities + swap_perturb_prob = 0.15 # Probability of performing a small-large circle swap + cluster_perturb_prob = 0.1 # Probability of performing a clustered perturbation + single_perturb_prob = 1.0 - swap_perturb_prob - cluster_perturb_prob # Remainder for single circle move + + # Stagnation detection and escape parameters + stagnation_counter = 0 + stagnation_threshold = 1200 # Iterations without finding a new best to trigger a boost + perturb_boost = 1.0 + boost_factor = 3.5 # Stronger kick + boost_decay = 0.96 # Slightly faster decay + temp_reheat_factor_on_stagnation = 0.6 # More significant reheating + + # Adaptive compute_max_radii iterations + min_radii_iters = 100 + max_radii_iters = 750 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + # Logarithmic decay for temperature and perturbation strength + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Adaptive `compute_max_radii` iterations: fewer early, more later + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) + + current_temp = temp_schedule # Use the scheduled temperature by default + + # Check for stagnation and apply a temporary perturbation boost and temperature reheat + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp = temp_schedule + initial_temp * temp_reheat_factor_on_stagnation # Reheat temperature + stagnation_counter = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_perturb_prob: + # Type 1: Swap Perturbation (reintroduced) + sorted_indices = np.argsort(current_radii) + if self.n > 1: + num_small_candidates = max(1, self.n // 4) # Consider top 25% smallest + num_large_candidates = max(1, self.n // 4) # Consider top 25% largest + + small_circles_indices = sorted_indices[:num_small_candidates] + large_circles_indices = sorted_indices[-num_large_candidates:] + + if len(small_circles_indices) > 0 and len(large_circles_indices) > 0: + idx_small = np.random.choice(small_circles_indices) + idx_large = np.random.choice(large_circles_indices) + + # Swap positions + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() + elif rand_val < swap_perturb_prob + cluster_perturb_prob: + # Type 2: Clustered Perturbation (new) + # Select a primary circle using context-aware selection + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + + # Find its 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Ensure the primary circle itself is not considered a neighbor (distance is 0) + distances_to_primary[primary_idx] = np.inf + neighbor_indices = np.argsort(distances_to_primary)[:2] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate effective perturbation for the cluster (scaled down) + effective_perturb_strength = self._adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost + cluster_move_strength = effective_perturb_strength * 0.7 # Cluster moves are generally smaller + + displacement = np.random.uniform(-cluster_move_strength, cluster_move_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Type 3: Single Circle Displacement (existing) + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + effective_perturb_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration with adaptive radii iterations + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + stagnation_counter = 0 # Reset on new best + else: + stagnation_counter += 1 # Accepted a state, but it wasn't the best + else: + stagnation_counter += 1 # Rejected a state + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, + amplitude=0.08, + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( + total_iterations=35000, # Increased iterations for more thorough search + initial_temp=0.0008, # Slightly adjusted initial temp + final_temp=1e-10, # Slightly lower final temp + initial_perturb_strength=0.035, # Slightly adjusted initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/original.py new file mode 100644 index 0000000000000000000000000000000000000000..421f394661b30ee7d16c20af349163083a3772f3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/original.py @@ -0,0 +1,248 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +def _generate_void_config(n, void_center, amplitude, sigma): + """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + +def relaxation_stage(centers, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation (jiggle) phase.""" + relaxed_centers = centers.copy() + for _ in range(iters): + diff = relaxed_centers[:, np.newaxis, :] - relaxed_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, relaxed_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, relaxed_centers[:, 1] - (1 - boundary_margin)) + + relaxed_centers += step_size * forces + relaxed_centers = np.clip(relaxed_centers, 0.0, 1.0) + return relaxed_centers + +def _select_circle_context_aware(n, current_radii, current_centers): + """Intelligently selects a circle to perturb based on radius, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(n) + for i in range(n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(n, p=selection_probs) + +def _adaptive_perturbation_strength(base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + +def annealing_stage(centers, n): + """Performs the main simulated annealing optimization stage.""" + current_centers = centers.copy() + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_sum_radii = current_sum_radii + + # SA Parameters + total_iterations = 20000 + initial_temp = 0.0008 + final_temp = 1e-9 + initial_perturb_strength = 0.035 + final_perturb_strength = 0.0001 + + # Stagnation Escape Parameters + stagnation_counter = 0 + stagnation_threshold = 800 + perturb_boost = 1.0 + boost_factor = 3.0 + boost_decay = 0.98 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + + # Annealing schedules + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Stagnation escape: boost perturbation and reheat temperature + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + temp = temp_schedule + initial_temp * 0.4 # Reheat + stagnation_counter = 0 + else: + temp = temp_schedule + + candidate_centers = current_centers.copy() + + circle_idx = _select_circle_context_aware(n, current_radii, current_centers) + + effective_perturb_strength = _adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + return best_centers + +def initialization_stage(n): + """Performs a multi-start initialization and selects the best starting point.""" + best_initial_sum_radii = -1.0 + best_initial_centers = None + + # Diverse void configurations to try + void_configs = [ + (np.array([0.4, 0.2]), 0.06), + (np.array([0.2, 0.4]), 0.05), + (np.array([0.6, 0.8]), 0.07), + (np.array([0.8, 0.6]), 0.065), + (np.array([0.5, 0.5]), 0.05), + (np.random.uniform(0.3, 0.7, 2), 0.08), + ] + + for void_center, amplitude in void_configs: + candidate_centers = _generate_void_config(n, void_center, amplitude, sigma=0.15) + + # Settle with a very quick relaxation + relaxed_centers = relaxation_stage( + candidate_centers, iters=150, step_size=0.002, + repulsion_strength=0.02, boundary_strength=0.07, + repulsion_threshold=0.2, boundary_margin=0.04 + ) + candidate_radii = compute_max_radii(relaxed_centers) + candidate_sum_radii = np.sum(candidate_radii) + + if candidate_sum_radii > best_initial_sum_radii: + best_initial_sum_radii = candidate_sum_radii + best_initial_centers = relaxed_centers.copy() + + return best_initial_centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a functional, + multi-stage optimization pipeline. + """ + n = 26 + + # Stage 1: Multi-Start Initialization to find a robust starting point + initial_centers = initialization_stage(n) + + # Stage 2: Main Simulated Annealing optimization + # The initial relaxation is now part of the initialization stage, + # so we can directly proceed to annealing. + annealed_centers = annealing_stage(initial_centers, n) + + # Stage 3: Final gentle polish using relaxation + final_centers = relaxation_stage( + annealed_centers, iters=300, step_size=0.0001, + repulsion_strength=0.001, boundary_strength=0.005, + repulsion_threshold=0.18, boundary_margin=0.02 + ) + + # Final evaluation + final_radii = compute_max_radii(final_centers) + annealed_radii = compute_max_radii(annealed_centers) + + # Return the best result between the SA output and the polished version + if np.sum(final_radii) > np.sum(annealed_radii): + return final_centers, final_radii + else: + return annealed_centers, annealed_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..fb3b13a502e9db7274df5477b66d01fed12d879c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_176/main.py:118: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..76865dc4f793dffb0a5fd6037479c5dd915a3567 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_176/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_176/results +Run 1/1 completed in 85.38 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.4256927342960375 + public: {'centers_str': ' centers[0] = (0.0744, 0.0744)\n centers[1] = (0.8907, 0.2810)\n centers[2] = (0.6943, 0.0843)\n centers[3] = (0.3647, 0.6034)\n centers[4] = (0.6956, 0.7199)\n centers[5] = (0.2684, 0.3679)\n centers[6] = (0.4338, 0.2771)\n centers[7] = (0.6941, 0.3059)\n centers[8] = (0.2826, 0.1098)\n centers[9] = (0.5271, 0.0917)\n centers[10] = (0.9134, 0.9135)\n centers[11] = (0.1150, 0.2594)\n centers[12] = (0.5084, 0.5116)\n centers[13] = (0.7275, 0.5571)\n centers[14] = (0.8979, 0.4472)\n centers[15] = (0.1006, 0.7086)\n centers[16] = (0.2923, 0.7030)\n centers[17] = (0.4948, 0.6994)\n centers[18] = (0.8822, 0.1204)\n centers[19] = (0.1219, 0.4962)\n centers[20] = (0.1002, 0.9001)\n centers[21] = (0.3007, 0.9015)\n centers[22] = (0.4996, 0.9009)\n centers[23] = (0.7156, 0.8870)\n centers[24] = (0.8822, 0.7115)\n centers[25] = (0.3328, 0.5174)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.4256927342960375} + visualization_path: + execution_time_mean: 85.38485767599195 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..95a5d9eed22ee34ed67d2bcfdd0b45c67b11d766 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.4256927342960375, + "public": { + "centers_str": " centers[0] = (0.0744, 0.0744)\n centers[1] = (0.8907, 0.2810)\n centers[2] = (0.6943, 0.0843)\n centers[3] = (0.3647, 0.6034)\n centers[4] = (0.6956, 0.7199)\n centers[5] = (0.2684, 0.3679)\n centers[6] = (0.4338, 0.2771)\n centers[7] = (0.6941, 0.3059)\n centers[8] = (0.2826, 0.1098)\n centers[9] = (0.5271, 0.0917)\n centers[10] = (0.9134, 0.9135)\n centers[11] = (0.1150, 0.2594)\n centers[12] = (0.5084, 0.5116)\n centers[13] = (0.7275, 0.5571)\n centers[14] = (0.8979, 0.4472)\n centers[15] = (0.1006, 0.7086)\n centers[16] = (0.2923, 0.7030)\n centers[17] = (0.4948, 0.6994)\n centers[18] = (0.8822, 0.1204)\n centers[19] = (0.1219, 0.4962)\n centers[20] = (0.1002, 0.9001)\n centers[21] = (0.3007, 0.9015)\n centers[22] = (0.4996, 0.9009)\n centers[23] = (0.7156, 0.8870)\n centers[24] = (0.8822, 0.7115)\n centers[25] = (0.3328, 0.5174)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.4256927342960375 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_176/results/packing_viz.png", + "execution_time_mean": 85.38485767599195, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..19b2d41dd7cf524e6e725aad4ff88fec916ab61a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_176/rewrite.txt @@ -0,0 +1,357 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: Maximum iterations for convergence. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): # Use dynamic max_iterations + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] # (N, N, 2) + dists = np.linalg.norm(diff, axis=2) # (N, N) + + # Mask out self-interaction by setting diagonal distances to a very large value + np.fill_diagonal(dists, np.inf) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors F_ij (force on i from j) + # F_ij direction is (centers[i] - centers[j]) / dists[i,j] + # Store unit vectors: normalized_diff[i,j] = (centers[i] - centers[j]) / dists[i,j] + normalized_diff = np.zeros_like(diff) + # Avoid division by zero where dists might be zero or inf (already handled diag to inf) + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # Sum force_magnitudes[i,j] * normalized_diff[i,j] over j for each i + # This correctly sums F_ij (force exerted by j on i) for all j!=i + forces_repulsion = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + forces += forces_repulsion + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _select_circle_context_aware(self, current_radii, current_centers): + """Intelligently selects a circle to perturb based on inverse radius, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) # Circles near boundary get higher weight + + neighbor_counts = np.zeros(self.n) + for i in range(self.n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 # Check for neighbors closer than 1.1 * sum of radii + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 # Subtract self + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) + + # Combine weights: smaller radius, closer to boundary, more crowded -> higher probability of selection + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + + return np.random.choice(self.n, p=selection_probs) + + def _adaptive_perturbation_strength(self, base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles, allowing them to move more freely.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + # Factor is larger for smaller relative_radius + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It incorporates multi-modal perturbations and adaptive `compute_max_radii` iterations. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Perturbation strategy probabilities + swap_perturb_prob = 0.15 # Probability of performing a small-large circle swap + cluster_perturb_prob = 0.1 # Probability of performing a clustered perturbation + single_perturb_prob = 1.0 - swap_perturb_prob - cluster_perturb_prob # Remainder for single circle move + + # Stagnation detection and escape parameters + stagnation_counter = 0 + stagnation_threshold = 1200 # Iterations without finding a new best to trigger a boost + perturb_boost = 1.0 + boost_factor = 3.5 # Stronger kick + boost_decay = 0.96 # Slightly faster decay + temp_reheat_factor_on_stagnation = 0.6 # More significant reheating + + # Adaptive compute_max_radii iterations + min_radii_iters = 100 + max_radii_iters = 750 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + # Logarithmic decay for temperature and perturbation strength + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Adaptive `compute_max_radii` iterations: fewer early, more later + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) + + current_temp = temp_schedule # Use the scheduled temperature by default + + # Check for stagnation and apply a temporary perturbation boost and temperature reheat + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp = temp_schedule + initial_temp * temp_reheat_factor_on_stagnation # Reheat temperature + stagnation_counter = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_perturb_prob: + # Type 1: Swap Perturbation (reintroduced) + sorted_indices = np.argsort(current_radii) + if self.n > 1: + num_small_candidates = max(1, self.n // 4) # Consider top 25% smallest + num_large_candidates = max(1, self.n // 4) # Consider top 25% largest + + small_circles_indices = sorted_indices[:num_small_candidates] + large_circles_indices = sorted_indices[-num_large_candidates:] + + if len(small_circles_indices) > 0 and len(large_circles_indices) > 0: + idx_small = np.random.choice(small_circles_indices) + idx_large = np.random.choice(large_circles_indices) + + # Swap positions + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() + elif rand_val < swap_perturb_prob + cluster_perturb_prob: + # Type 2: Clustered Perturbation (new) + # Select a primary circle using context-aware selection + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + + # Find its 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Ensure the primary circle itself is not considered a neighbor (distance is 0) + distances_to_primary[primary_idx] = np.inf + neighbor_indices = np.argsort(distances_to_primary)[:2] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate effective perturbation for the cluster (scaled down) + effective_perturb_strength = self._adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost + cluster_move_strength = effective_perturb_strength * 0.7 # Cluster moves are generally smaller + + displacement = np.random.uniform(-cluster_move_strength, cluster_move_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Type 3: Single Circle Displacement (existing) + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + effective_perturb_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration with adaptive radii iterations + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + stagnation_counter = 0 # Reset on new best + else: + stagnation_counter += 1 # Accepted a state, but it wasn't the best + else: + stagnation_counter += 1 # Rejected a state + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, + amplitude=0.08, + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( + total_iterations=35000, # Increased iterations for more thorough search + initial_temp=0.0008, # Slightly adjusted initial temp + final_temp=1e-10, # Slightly lower final temp + initial_perturb_strength=0.035, # Slightly adjusted initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a74d677030aded32d7bfebe865dfdc46489522b Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..08c4e2a126f922ba61ff22564c3d0b9fbca351bb --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_178/main.py:147: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..50bcde9acdc246d489d003b9b79fabc1ee75ba9f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_178/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_178/results +Run 1/1 completed in 826.78 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9393002141860824 + public: {'centers_str': ' centers[0] = (0.0781, 0.0781)\n centers[1] = (0.3213, 0.0780)\n centers[2] = (0.5023, 0.0995)\n centers[3] = (0.7001, 0.1000)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0780, 0.3213)\n centers[6] = (0.3214, 0.3214)\n centers[7] = (0.5023, 0.3005)\n centers[8] = (0.7001, 0.3000)\n centers[9] = (0.9000, 0.3000)\n centers[10] = (0.0995, 0.5023)\n centers[11] = (0.3005, 0.5023)\n centers[12] = (0.5001, 0.5001)\n centers[13] = (0.7000, 0.5000)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7001)\n centers[16] = (0.3000, 0.7001)\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.2000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9393002141860824} + visualization_path: + execution_time_mean: 826.7774525550194 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..1861e81e54d25b3d854dc419e7bc72d1a60ce942 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9393002141860824, + "public": { + "centers_str": " centers[0] = (0.0781, 0.0781)\n centers[1] = (0.3213, 0.0780)\n centers[2] = (0.5023, 0.0995)\n centers[3] = (0.7001, 0.1000)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0780, 0.3213)\n centers[6] = (0.3214, 0.3214)\n centers[7] = (0.5023, 0.3005)\n centers[8] = (0.7001, 0.3000)\n centers[9] = (0.9000, 0.3000)\n centers[10] = (0.0995, 0.5023)\n centers[11] = (0.3005, 0.5023)\n centers[12] = (0.5001, 0.5001)\n centers[13] = (0.7000, 0.5000)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7001)\n centers[16] = (0.3000, 0.7001)\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.2000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9393002141860824 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_178/results/packing_viz.png", + "execution_time_mean": 826.7774525550194, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c50e489952c42243fa471a9309f086d36da22aeb Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..ec5bda8e9eaab878279f747bc638febbd7f17d7a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/edit.diff @@ -0,0 +1,412 @@ +--- a/original.py ++++ b/original.py +@@ -1,257 +1,273 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + +-# compute_max_radii remains unchanged as it's a robust evaluation function. +-def compute_max_radii(centers): ++def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. ++ ++ Args: ++ centers: np.array of shape (n, 2) with (x, y) coordinates ++ max_iterations: Maximum iterations for convergence. ++ ++ Returns: ++ np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + +- for _ in range(500): ++ for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True ++ else: ++ radii[i] = 0.0 ++ radii[j] = 0.0 ++ changes_made = True + if not changes_made: + break + return radii + + class CirclePacker: + """ +- Encapsulates the logic for packing circles using a hybrid strategy: +- 1. Multi-start initialization to find a promising starting configuration. +- 2. An advanced Simulated Annealing (SA) search with: +- - Intelligent, context-aware circle selection for perturbation. +- - Adaptive perturbation strength based on circle size. +- - Stagnation detection and escape mechanism. +- 3. Vectorized force-directed relaxation for initial settling and final polishing. +- """ +- def __init__(self, n): ++ A class to encapsulate the logic for packing circles using a hybrid approach: ++ 1. Initial placement with a void to break symmetry. ++ 2. A force-directed relaxation phase to settle the initial state. ++ 3. A primary simulated annealing search with multi-modal perturbations. ++ 4. A final polishing phase. ++ """ ++ ++ def __init__(self, n=26): ++ """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + +- def _initialize_grid_with_void(self, void_center, amplitude, sigma): +- """Initializes centers from a 5x5 grid deformed by a Gaussian push.""" ++ def _initial_placement_with_void(self, void_center, amplitude, sigma): ++ """ ++ Generates an initial configuration from a 5x5 grid deformed by a Gaussian push. ++ """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center +- return np.clip(initial_centers, 0.0, 1.0) +- +- def _relax_phase(self, centers_to_relax, iters, step_size, repulsion_strength, +- boundary_strength, repulsion_threshold, boundary_margin): +- """Performs a vectorized force-directed relaxation (jiggle) phase.""" ++ self.centers = np.clip(initial_centers, 0.0, 1.0) ++ ++ def _force_directed_relaxation(self, iters, step_size, repulsion_strength, ++ boundary_strength, repulsion_threshold, boundary_margin): ++ """ ++ Applies a vectorized force-directed relaxation to the current centers. ++ """ + for _ in range(iters): +- diff = centers_to_relax[:, np.newaxis, :] - centers_to_relax[np.newaxis, :, :] ++ diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) +- +- mask = (dists > 1e-9) & (dists < repulsion_threshold) +- +- force_scalar = np.zeros_like(dists) +- force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] +- +- force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +- forces = np.sum(force_vectors, axis=1) +- +- forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - centers_to_relax[:, 0]) +- forces[:, 0] -= boundary_strength * np.maximum(0, centers_to_relax[:, 0] - (1 - boundary_margin)) +- forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - centers_to_relax[:, 1]) +- forces[:, 1] -= boundary_strength * np.maximum(0, centers_to_relax[:, 1] - (1 - boundary_margin)) +- +- centers_to_relax += step_size * forces +- centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) +- return centers_to_relax +- +- def _select_circle_for_perturbation(self, current_radii, current_centers): +- """Intelligently selects a circle to perturb based on radius, boundary proximity, and crowding.""" ++ np.fill_diagonal(dists, np.inf) ++ ++ repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) ++ ++ force_magnitudes = np.zeros_like(dists) ++ force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] ++ ++ normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) ++ ++ forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) ++ forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) ++ forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) ++ forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) ++ ++ self.centers += step_size * forces ++ self.centers = np.clip(self.centers, 0.0, 1.0) ++ ++ def _select_circle_context_aware(self, current_radii, current_centers): ++ """Intelligently selects a circle to perturb based on size, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) +- + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(self.n) + for i in range(self.n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) +- # Count neighbors closer than 1.1 times the sum of radii + crowd_dist = (current_radii[i] + current_radii) * 1.1 +- neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 # Subtract self ++ neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) +- ++ + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) +- + return np.random.choice(self.n, p=selection_probs) + +- def _adaptive_perturbation(self, base_strength, circle_idx, current_radii): ++ def _adaptive_perturbation_strength(self, base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r +- # Factor is larger for smaller relative_radius + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + +- def pack(self): +- """Executes the full packing process.""" +- +- # --- 1. Multi-Start Initialization --- +- best_initial_sum_radii = -1.0 +- best_initial_centers = None +- +- # Try diverse void centers to find a promising start. +- void_configs = [ +- (np.random.uniform(0.3, 0.7, 2), 0.08), # Random +- (np.array([0.4, 0.2]), 0.06), +- (np.array([0.2, 0.4]), 0.05), +- (np.array([0.6, 0.8]), 0.07), +- (np.array([0.8, 0.6]), 0.065), +- (np.array([0.5, 0.5]), 0.05), +- ] +- +- for void_center, amplitude in void_configs: +- candidate_centers = self._initialize_grid_with_void(void_center, amplitude, sigma=0.15) +- +- # Settle the initial configuration with a quick relaxation. +- relaxed_centers = self._relax_phase( +- candidate_centers.copy(), iters=200, step_size=0.002, +- repulsion_strength=0.02, boundary_strength=0.07, +- repulsion_threshold=0.2, boundary_margin=0.04 +- ) +- candidate_radii = compute_max_radii(relaxed_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- if candidate_sum_radii > best_initial_sum_radii: +- best_initial_sum_radii = candidate_sum_radii +- best_initial_centers = relaxed_centers.copy() +- +- # --- 2. Simulated Annealing Main Loop --- +- current_centers = best_initial_centers +- current_radii = compute_max_radii(current_centers) +- current_sum_radii = np.sum(current_radii) +- +- best_centers = current_centers.copy() +- best_sum_radii = current_sum_radii +- +- # SA Parameters +- total_iterations = 25000 +- initial_temp = 0.0008 +- final_temp = 1e-9 +- initial_perturb_strength = 0.035 +- final_perturb_strength = 0.0001 +- +- # Stagnation Escape Parameters ++ def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, ++ initial_perturb_strength, final_perturb_strength): ++ """ ++ Performs SA with multi-modal perturbations and advanced stagnation escape. ++ """ ++ best_centers = self.centers.copy() ++ best_radii = compute_max_radii(best_centers) ++ best_sum_radii = np.sum(best_radii) ++ ++ current_centers = best_centers.copy() ++ current_radii = best_radii.copy() ++ current_sum_radii = best_sum_radii ++ ++ swap_perturb_prob = 0.15 ++ cluster_perturb_prob = 0.10 ++ + stagnation_counter = 0 +- stagnation_threshold = 800 # More patience before a kick ++ stagnation_threshold = 1200 + perturb_boost = 1.0 +- boost_factor = 3.0 # A stronger kick +- boost_decay = 0.98 ++ boost_factor = 3.5 ++ boost_decay = 0.96 ++ temp_reheat_factor = 0.6 ++ ++ min_radii_iters, max_radii_iters = 100, 750 + + for iteration in range(total_iterations): + progress = iteration / total_iterations +- # Standard annealing schedule for temperature and perturbation + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) +- +- temp = temp_schedule # Use the scheduled temperature by default +- +- # Stagnation escape: apply a "reheating" and "perturbation storm" ++ ++ radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) ++ current_temp = temp_schedule ++ + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor +- # Reheat: temporarily raise the temperature to accept more radical changes +- temp = temp_schedule + initial_temp * 0.5 ++ current_temp += initial_temp * temp_reheat_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() +- +- circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) +- +- effective_perturb_strength = self._adaptive_perturbation(base_perturb_strength, circle_idx, current_radii) * perturb_boost +- +- displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +- candidate_centers[circle_idx] += displacement +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +- ++ rand_val = np.random.rand() ++ ++ if rand_val < swap_perturb_prob: ++ sorted_indices = np.argsort(current_radii) ++ if self.n > 1: ++ num_candidates = max(1, self.n // 4) ++ small_idx = np.random.choice(sorted_indices[:num_candidates]) ++ large_idx = np.random.choice(sorted_indices[-num_candidates:]) ++ if small_idx != large_idx: ++ candidate_centers[small_idx], candidate_centers[large_idx] = \ ++ candidate_centers[large_idx].copy(), candidate_centers[small_idx].copy() ++ ++ elif rand_val < swap_perturb_prob + cluster_perturb_prob: ++ primary_idx = self._select_circle_context_aware(current_radii, current_centers) ++ distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) ++ distances[primary_idx] = np.inf ++ neighbor_indices = np.argsort(distances)[:2] ++ indices_to_perturb = np.append(neighbor_indices, primary_idx) ++ ++ eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost * 0.7 ++ displacement = np.random.uniform(-eff_strength, eff_strength, 2) ++ candidate_centers[indices_to_perturb] += displacement ++ ++ else: ++ circle_idx = self._select_circle_context_aware(current_radii, current_centers) ++ eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost ++ displacement = np.random.uniform(-eff_strength, eff_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ ++ candidate_centers = np.clip(candidate_centers, 0.0, 1.0) ++ + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + +- candidate_radii = compute_max_radii(candidate_centers) ++ candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii +- if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): +- current_centers = candidate_centers +- current_radii = candidate_radii +- current_sum_radii = candidate_sum_radii +- ++ if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): ++ current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii + if current_sum_radii > best_sum_radii: +- best_sum_radii = current_sum_radii +- best_centers = current_centers.copy() ++ best_sum_radii, best_centers = current_sum_radii, current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + +- # --- 3. Final Gentle Polish --- +- final_centers = self._relax_phase( +- best_centers, iters=300, step_size=0.0001, repulsion_strength=0.001, ++ self.centers = best_centers ++ return compute_max_radii(best_centers) ++ ++ def pack(self): ++ """ ++ Orchestrates the entire packing process. ++ """ ++ # 1. Initial placement with a randomized void. ++ self._initial_placement_with_void( ++ void_center=np.random.uniform(0.3, 0.7, 2), ++ amplitude=0.08, ++ sigma=0.15 ++ ) ++ ++ # 2. Aggressive force-directed relaxation to settle. ++ self._force_directed_relaxation( ++ iters=500, step_size=0.002, repulsion_strength=0.02, ++ boundary_strength=0.08, repulsion_threshold=0.19, boundary_margin=0.04 ++ ) ++ ++ # 3. Main Simulated Annealing search for global optimization. ++ self._simulated_annealing_search( ++ total_iterations=35000, initial_temp=0.0008, final_temp=1e-10, ++ initial_perturb_strength=0.035, final_perturb_strength=0.0001 ++ ) ++ ++ # 4. Final gentle relaxation for polishing. ++ self._force_directed_relaxation( ++ iters=300, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 + ) +- final_radii = compute_max_radii(final_centers) +- +- # Return the best result between the SA output and the polished version +- annealed_radii = compute_max_radii(best_centers) +- if np.sum(final_radii) > np.sum(annealed_radii): +- return final_centers, final_radii +- else: +- return best_centers, annealed_radii ++ ++ final_radii = compute_max_radii(self.centers, max_iterations=1000) ++ return self.centers, final_radii + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the advanced CirclePacker class. + """ +- n = 26 +- packer = CirclePacker(n) ++ packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/main.py new file mode 100644 index 0000000000000000000000000000000000000000..f86115db3989e8fef06e14163e4b0612c39c4b05 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/main.py @@ -0,0 +1,273 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: Maximum iterations for convergence. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the logic for packing circles using a hybrid approach: + 1. Initial placement with a void to break symmetry. + 2. A force-directed relaxation phase to settle the initial state. + 3. A primary simulated annealing search with multi-modal perturbations. + 4. A final polishing phase. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void(self, void_center, amplitude, sigma): + """ + Generates an initial configuration from a 5x5 grid deformed by a Gaussian push. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a vectorized force-directed relaxation to the current centers. + """ + for _ in range(iters): + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + np.fill_diagonal(dists, np.inf) + + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _select_circle_context_aware(self, current_radii, current_centers): + """Intelligently selects a circle to perturb based on size, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(self.n) + for i in range(self.n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(self.n, p=selection_probs) + + def _adaptive_perturbation_strength(self, base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs SA with multi-modal perturbations and advanced stagnation escape. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + swap_perturb_prob = 0.15 + cluster_perturb_prob = 0.10 + + stagnation_counter = 0 + stagnation_threshold = 1200 + perturb_boost = 1.0 + boost_factor = 3.5 + boost_decay = 0.96 + temp_reheat_factor = 0.6 + + min_radii_iters, max_radii_iters = 100, 750 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) + current_temp = temp_schedule + + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp += initial_temp * temp_reheat_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_perturb_prob: + sorted_indices = np.argsort(current_radii) + if self.n > 1: + num_candidates = max(1, self.n // 4) + small_idx = np.random.choice(sorted_indices[:num_candidates]) + large_idx = np.random.choice(sorted_indices[-num_candidates:]) + if small_idx != large_idx: + candidate_centers[small_idx], candidate_centers[large_idx] = \ + candidate_centers[large_idx].copy(), candidate_centers[small_idx].copy() + + elif rand_val < swap_perturb_prob + cluster_perturb_prob: + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost * 0.7 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement + + else: + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[circle_idx] += displacement + + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): + current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii + if current_sum_radii > best_sum_radii: + best_sum_radii, best_centers = current_sum_radii, current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + self.centers = best_centers + return compute_max_radii(best_centers) + + def pack(self): + """ + Orchestrates the entire packing process. + """ + # 1. Initial placement with a randomized void. + self._initial_placement_with_void( + void_center=np.random.uniform(0.3, 0.7, 2), + amplitude=0.08, + sigma=0.15 + ) + + # 2. Aggressive force-directed relaxation to settle. + self._force_directed_relaxation( + iters=500, step_size=0.002, repulsion_strength=0.02, + boundary_strength=0.08, repulsion_threshold=0.19, boundary_margin=0.04 + ) + + # 3. Main Simulated Annealing search for global optimization. + self._simulated_annealing_search( + total_iterations=35000, initial_temp=0.0008, final_temp=1e-10, + initial_perturb_strength=0.035, final_perturb_strength=0.0001 + ) + + # 4. Final gentle relaxation for polishing. + self._force_directed_relaxation( + iters=300, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 + ) + + final_radii = compute_max_radii(self.centers, max_iterations=1000) + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the advanced CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/original.py new file mode 100644 index 0000000000000000000000000000000000000000..1b942d929f6fc55c664968802590eff7e00200e9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/original.py @@ -0,0 +1,257 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + Encapsulates the logic for packing circles using a hybrid strategy: + 1. Multi-start initialization to find a promising starting configuration. + 2. An advanced Simulated Annealing (SA) search with: + - Intelligent, context-aware circle selection for perturbation. + - Adaptive perturbation strength based on circle size. + - Stagnation detection and escape mechanism. + 3. Vectorized force-directed relaxation for initial settling and final polishing. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + + def _initialize_grid_with_void(self, void_center, amplitude, sigma): + """Initializes centers from a 5x5 grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + def _relax_phase(self, centers_to_relax, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation (jiggle) phase.""" + for _ in range(iters): + diff = centers_to_relax[:, np.newaxis, :] - centers_to_relax[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - centers_to_relax[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, centers_to_relax[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - centers_to_relax[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, centers_to_relax[:, 1] - (1 - boundary_margin)) + + centers_to_relax += step_size * forces + centers_to_relax = np.clip(centers_to_relax, 0.0, 1.0) + return centers_to_relax + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """Intelligently selects a circle to perturb based on radius, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(self.n) + for i in range(self.n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + # Count neighbors closer than 1.1 times the sum of radii + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 # Subtract self + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + + return np.random.choice(self.n, p=selection_probs) + + def _adaptive_perturbation(self, base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + # Factor is larger for smaller relative_radius + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + + def pack(self): + """Executes the full packing process.""" + + # --- 1. Multi-Start Initialization --- + best_initial_sum_radii = -1.0 + best_initial_centers = None + + # Try diverse void centers to find a promising start. + void_configs = [ + (np.random.uniform(0.3, 0.7, 2), 0.08), # Random + (np.array([0.4, 0.2]), 0.06), + (np.array([0.2, 0.4]), 0.05), + (np.array([0.6, 0.8]), 0.07), + (np.array([0.8, 0.6]), 0.065), + (np.array([0.5, 0.5]), 0.05), + ] + + for void_center, amplitude in void_configs: + candidate_centers = self._initialize_grid_with_void(void_center, amplitude, sigma=0.15) + + # Settle the initial configuration with a quick relaxation. + relaxed_centers = self._relax_phase( + candidate_centers.copy(), iters=200, step_size=0.002, + repulsion_strength=0.02, boundary_strength=0.07, + repulsion_threshold=0.2, boundary_margin=0.04 + ) + candidate_radii = compute_max_radii(relaxed_centers) + candidate_sum_radii = np.sum(candidate_radii) + + if candidate_sum_radii > best_initial_sum_radii: + best_initial_sum_radii = candidate_sum_radii + best_initial_centers = relaxed_centers.copy() + + # --- 2. Simulated Annealing Main Loop --- + current_centers = best_initial_centers + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_sum_radii = current_sum_radii + + # SA Parameters + total_iterations = 25000 + initial_temp = 0.0008 + final_temp = 1e-9 + initial_perturb_strength = 0.035 + final_perturb_strength = 0.0001 + + # Stagnation Escape Parameters + stagnation_counter = 0 + stagnation_threshold = 800 # More patience before a kick + perturb_boost = 1.0 + boost_factor = 3.0 # A stronger kick + boost_decay = 0.98 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + # Standard annealing schedule for temperature and perturbation + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + temp = temp_schedule # Use the scheduled temperature by default + + # Stagnation escape: apply a "reheating" and "perturbation storm" + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + # Reheat: temporarily raise the temperature to accept more radical changes + temp = temp_schedule + initial_temp * 0.5 + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + + effective_perturb_strength = self._adaptive_perturbation(base_perturb_strength, circle_idx, current_radii) * perturb_boost + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + # --- 3. Final Gentle Polish --- + final_centers = self._relax_phase( + best_centers, iters=300, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 + ) + final_radii = compute_max_radii(final_centers) + + # Return the best result between the SA output and the polished version + annealed_radii = compute_max_radii(best_centers) + if np.sum(final_radii) > np.sum(annealed_radii): + return final_centers, final_radii + else: + return best_centers, annealed_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the advanced CirclePacker class. + """ + n = 26 + packer = CirclePacker(n) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..74e0730c1c068ff5f4bce05823d662ec469e6896 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_179/main.py:95: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..e410cf362f07632ae0b0828cd6497bb4ab54f4a6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_179/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_179/results +Run 1/1 completed in 87.66 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.3807136986181163 + public: {'centers_str': ' centers[0] = (0.0975, 0.0975)\n centers[1] = (0.6094, 0.6499)\n centers[2] = (0.6931, 0.2689)\n centers[3] = (0.9002, 0.0998)\n centers[4] = (0.3930, 0.5487)\n centers[5] = (0.5286, 0.8881)\n centers[6] = (0.3031, 0.8549)\n centers[7] = (0.4765, 0.2739)\n centers[8] = (0.2908, 0.4606)\n centers[9] = (0.8995, 0.2994)\n centers[10] = (0.9023, 0.6905)\n centers[11] = (0.6695, 0.4877)\n centers[12] = (0.7075, 0.0936)\n centers[13] = (0.1038, 0.5027)\n centers[14] = (0.9035, 0.4963)\n centers[15] = (0.0875, 0.7136)\n centers[16] = (0.2589, 0.6360)\n centers[17] = (0.2947, 0.0984)\n centers[18] = (0.7043, 0.7296)\n centers[19] = (0.4814, 0.6698)\n centers[20] = (0.0996, 0.9004)\n centers[21] = (0.8936, 0.8918)\n centers[22] = (0.3237, 0.2904)\n centers[23] = (0.7072, 0.9181)\n centers[24] = (0.5051, 0.1093)\n centers[25] = (0.1138, 0.2853)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.3807136986181163} + visualization_path: + execution_time_mean: 87.66397934779525 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..5508ad598cff4afdfa58ebf8f47acd35a00657e0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.3807136986181163, + "public": { + "centers_str": " centers[0] = (0.0975, 0.0975)\n centers[1] = (0.6094, 0.6499)\n centers[2] = (0.6931, 0.2689)\n centers[3] = (0.9002, 0.0998)\n centers[4] = (0.3930, 0.5487)\n centers[5] = (0.5286, 0.8881)\n centers[6] = (0.3031, 0.8549)\n centers[7] = (0.4765, 0.2739)\n centers[8] = (0.2908, 0.4606)\n centers[9] = (0.8995, 0.2994)\n centers[10] = (0.9023, 0.6905)\n centers[11] = (0.6695, 0.4877)\n centers[12] = (0.7075, 0.0936)\n centers[13] = (0.1038, 0.5027)\n centers[14] = (0.9035, 0.4963)\n centers[15] = (0.0875, 0.7136)\n centers[16] = (0.2589, 0.6360)\n centers[17] = (0.2947, 0.0984)\n centers[18] = (0.7043, 0.7296)\n centers[19] = (0.4814, 0.6698)\n centers[20] = (0.0996, 0.9004)\n centers[21] = (0.8936, 0.8918)\n centers[22] = (0.3237, 0.2904)\n centers[23] = (0.7072, 0.9181)\n centers[24] = (0.5051, 0.1093)\n centers[25] = (0.1138, 0.2853)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.3807136986181163 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_179/results/packing_viz.png", + "execution_time_mean": 87.66397934779525, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..692bd40c4aefdd7c7fc6f755eb4ed81435ff3413 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_179/rewrite.txt @@ -0,0 +1,264 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: Maximum iterations for convergence. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the logic for packing circles using a hybrid approach: + 1. Initial placement with a void to break symmetry. + 2. A force-directed relaxation phase to settle the initial state. + 3. A primary simulated annealing search with multi-modal perturbations. + 4. A final polishing phase. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void(self, void_center, amplitude, sigma): + """ + Generates an initial configuration from a 5x5 grid deformed by a Gaussian push. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a vectorized force-directed relaxation to the current centers. + """ + for _ in range(iters): + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + np.fill_diagonal(dists, np.inf) + + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _select_circle_context_aware(self, current_radii, current_centers): + """Intelligently selects a circle to perturb based on size, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(self.n) + for i in range(self.n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(self.n, p=selection_probs) + + def _adaptive_perturbation_strength(self, base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs SA with multi-modal perturbations and advanced stagnation escape. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + swap_perturb_prob = 0.15 + cluster_perturb_prob = 0.10 + + stagnation_counter = 0 + stagnation_threshold = 1200 + perturb_boost = 1.0 + boost_factor = 3.5 + boost_decay = 0.96 + temp_reheat_factor = 0.6 + + min_radii_iters, max_radii_iters = 100, 750 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) + current_temp = temp_schedule + + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp += initial_temp * temp_reheat_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_perturb_prob: + sorted_indices = np.argsort(current_radii) + if self.n > 1: + num_candidates = max(1, self.n // 4) + small_idx = np.random.choice(sorted_indices[:num_candidates]) + large_idx = np.random.choice(sorted_indices[-num_candidates:]) + if small_idx != large_idx: + candidate_centers[small_idx], candidate_centers[large_idx] = \ + candidate_centers[large_idx].copy(), candidate_centers[small_idx].copy() + + elif rand_val < swap_perturb_prob + cluster_perturb_prob: + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost * 0.7 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement + + else: + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[circle_idx] += displacement + + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): + current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii + if current_sum_radii > best_sum_radii: + best_sum_radii, best_centers = current_sum_radii, current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + self.centers = best_centers + return compute_max_radii(best_centers) + + def pack(self): + """ + Orchestrates the entire packing process. + """ + # 1. Initial placement with a randomized void. + self._initial_placement_with_void( + void_center=np.random.uniform(0.3, 0.7, 2), + amplitude=0.08, + sigma=0.15 + ) + + # 2. Aggressive force-directed relaxation to settle. + self._force_directed_relaxation( + iters=500, step_size=0.002, repulsion_strength=0.02, + boundary_strength=0.08, repulsion_threshold=0.19, boundary_margin=0.04 + ) + + # 3. Main Simulated Annealing search for global optimization. + self._simulated_annealing_search( + total_iterations=35000, initial_temp=0.0008, final_temp=1e-10, + initial_perturb_strength=0.035, final_perturb_strength=0.0001 + ) + + # 4. Final gentle relaxation for polishing. + self._force_directed_relaxation( + iters=300, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 + ) + + final_radii = compute_max_radii(self.centers, max_iterations=1000) + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the advanced CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b35634d94e106adde60b04843843ec547aee8616 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..574f5f20e95994f07b43203b593e20ede13cea63 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/edit.diff @@ -0,0 +1,135 @@ +--- a/original.py ++++ b/original.py +@@ -1,116 +1,116 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Using a 5-5-6-5-5 column-like structure. + # This structure is inspired by known good packings for N=26 and provides + # much better space utilization than the previous concentric ring model. + # It avoids the need for clipping, which created tiny, inefficient circles. + + # x-coordinates for the 5 columns + x_cols = np.linspace(0.1, 0.9, 5) + +- # y-coordinates for columns with 5 circles +- y_5 = np.linspace(0.1, 0.9, 5) +- +- # y-coordinates for the central column with 6 circles +- y_6 = np.linspace(1/12, 11/12, 6) ++ # Define y-coordinates for different column types to introduce staggering, ++ # creating a more hexagonal, denser packing. ++ y_col_center = np.linspace(1/12, 11/12, 6) # For the central 6-circle column ++ y_col_inner = np.linspace(1/6, 5/6, 5) # Staggered y-coords for inner 5-circle columns ++ y_col_outer = np.linspace(0.1, 0.9, 5) # Y-coords for outer 5-circle columns + + count = 0 +- # Arrange circles column by column ++ # Arrange circles column by column using the staggered y-coordinates + for i in range(5): + x = x_cols[i] + +- # The central column (i=2) has 6 circles +- if i == 2: +- for y in y_6: +- centers[count] = [x, y] +- count += 1 +- # The other four columns have 5 circles each +- else: +- for y in y_5: +- centers[count] = [x, y] +- count += 1 ++ if i == 2: # Central column (6 circles) ++ y_coords = y_col_center ++ elif i == 1 or i == 3: # Inner columns (5 circles), staggered ++ y_coords = y_col_inner ++ else: # Outer columns (5 circles), i=0 or i=4 ++ y_coords = y_col_outer ++ ++ for y in y_coords: ++ centers[count] = [x, y] ++ count += 1 + + # This construction places all centers within the (0,1) square, + # so no clipping is necessary. + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/main.py new file mode 100644 index 0000000000000000000000000000000000000000..ffb45717a4658be2df78b4daa41caf6212fbb645 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/main.py @@ -0,0 +1,116 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Using a 5-5-6-5-5 column-like structure. + # This structure is inspired by known good packings for N=26 and provides + # much better space utilization than the previous concentric ring model. + # It avoids the need for clipping, which created tiny, inefficient circles. + + # x-coordinates for the 5 columns + x_cols = np.linspace(0.1, 0.9, 5) + + # Define y-coordinates for different column types to introduce staggering, + # creating a more hexagonal, denser packing. + y_col_center = np.linspace(1/12, 11/12, 6) # For the central 6-circle column + y_col_inner = np.linspace(1/6, 5/6, 5) # Staggered y-coords for inner 5-circle columns + y_col_outer = np.linspace(0.1, 0.9, 5) # Y-coords for outer 5-circle columns + + count = 0 + # Arrange circles column by column using the staggered y-coordinates + for i in range(5): + x = x_cols[i] + + if i == 2: # Central column (6 circles) + y_coords = y_col_center + elif i == 1 or i == 3: # Inner columns (5 circles), staggered + y_coords = y_col_inner + else: # Outer columns (5 circles), i=0 or i=4 + y_coords = y_col_outer + + for y in y_coords: + centers[count] = [x, y] + count += 1 + + # This construction places all centers within the (0,1) square, + # so no clipping is necessary. + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/original.py new file mode 100644 index 0000000000000000000000000000000000000000..368fc9ec78544d28553669fe530269ccb33399cb --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/original.py @@ -0,0 +1,116 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Using a 5-5-6-5-5 column-like structure. + # This structure is inspired by known good packings for N=26 and provides + # much better space utilization than the previous concentric ring model. + # It avoids the need for clipping, which created tiny, inefficient circles. + + # x-coordinates for the 5 columns + x_cols = np.linspace(0.1, 0.9, 5) + + # y-coordinates for columns with 5 circles + y_5 = np.linspace(0.1, 0.9, 5) + + # y-coordinates for the central column with 6 circles + y_6 = np.linspace(1/12, 11/12, 6) + + count = 0 + # Arrange circles column by column + for i in range(5): + x = x_cols[i] + + # The central column (i=2) has 6 circles + if i == 2: + for y in y_6: + centers[count] = [x, y] + count += 1 + # The other four columns have 5 circles each + else: + for y in y_5: + centers[count] = [x, y] + count += 1 + + # This construction places all centers within the (0,1) square, + # so no clipping is necessary. + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..d42f7ef09a6f8b309b0bf80e72237076466c2e3e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_18/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_18/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.693681077716883 + 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.1667)\n centers[6] = (0.3000, 0.3333)\n centers[7] = (0.3000, 0.5000)\n centers[8] = (0.3000, 0.6667)\n centers[9] = (0.3000, 0.8333)\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.1667)\n centers[17] = (0.7000, 0.3333)\n centers[18] = (0.7000, 0.5000)\n centers[19] = (0.7000, 0.6667)\n centers[20] = (0.7000, 0.8333)\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} + private: {'reported_sum_of_radii': 1.693681077716883} + visualization_path: + execution_time_mean: 0.003721261862665415 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..60e4795c1ca48409b962e6448ee91096a4ed5026 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.693681077716883, + "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.1667)\n centers[6] = (0.3000, 0.3333)\n centers[7] = (0.3000, 0.5000)\n centers[8] = (0.3000, 0.6667)\n centers[9] = (0.3000, 0.8333)\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.1667)\n centers[17] = (0.7000, 0.3333)\n centers[18] = (0.7000, 0.5000)\n centers[19] = (0.7000, 0.6667)\n centers[20] = (0.7000, 0.8333)\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 + }, + "private": { + "reported_sum_of_radii": 1.693681077716883 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_18/results/packing_viz.png", + "execution_time_mean": 0.003721261862665415, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..7da8e6b11b759e2189a751c9b8f44106a3d7c864 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_18/search_replace.txt @@ -0,0 +1,77 @@ + +staggered_column_packing + + + +Based on my analysis of the visualization, I'm proposing an improvement to the circle packing strategy. + +**Analysis of Visualization:** + +1. **Spatial Distribution & Inefficient Patterns:** The current arrangement uses a `5-5-6-5-5` column structure. However, the visualization clearly shows that the columns are not staggered. All columns containing 5 circles use the same `y` coordinates, creating a rigid grid-like pattern. This results in the circles in adjacent columns being almost at the same y-level, which is an inefficient use of space. +2. **Unused Space:** This grid-like alignment leads to large diamond-shaped voids between the columns. The most significant consequence is that the circles in the central column (`x=0.5`) and the two adjacent to it (`x=0.3`, `x=0.7`) are severely compressed horizontally and are much smaller than the circles near the outer boundaries. This drastically reduces the total sum of radii. + +**Proposed Improvement:** + +To create a denser packing, I will introduce vertical staggering between the columns. This technique is inspired by hexagonal packing, which is the densest known packing for equal circles in the plane. By staggering the columns, circles can nestle into the gaps of their neighbors, allowing for a tighter overall arrangement and larger radii for the interior circles. + +My specific change is as follows: +* The central column of 6 circles remains the anchor of the structure. +* The two adjacent columns of 5 circles will have their y-positions shifted to fall into the "valleys" of the central column's circles. Their new y-coordinates are `np.linspace(1/6, 5/6, 5)`, which correspond to the midpoints of the central column's y-intervals. +* The two outermost columns of 5 circles will retain their original y-positions, which naturally creates a stagger with their new inner neighbors. + +This change directly targets the most significant inefficiency visible in the plot, aiming to increase the radii of the currently smallest circles and thus the total sum. + + + +<<<<<<< SEARCH + # x-coordinates for the 5 columns + x_cols = np.linspace(0.1, 0.9, 5) + + # y-coordinates for columns with 5 circles + y_5 = np.linspace(0.1, 0.9, 5) + + # y-coordinates for the central column with 6 circles + y_6 = np.linspace(1/12, 11/12, 6) + + count = 0 + # Arrange circles column by column + for i in range(5): + x = x_cols[i] + + # The central column (i=2) has 6 circles + if i == 2: + for y in y_6: + centers[count] = [x, y] + count += 1 + # The other four columns have 5 circles each + else: + for y in y_5: + centers[count] = [x, y] + count += 1 +======= + # x-coordinates for the 5 columns + x_cols = np.linspace(0.1, 0.9, 5) + + # Define y-coordinates for different column types to introduce staggering, + # creating a more hexagonal, denser packing. + y_col_center = np.linspace(1/12, 11/12, 6) # For the central 6-circle column + y_col_inner = np.linspace(1/6, 5/6, 5) # Staggered y-coords for inner 5-circle columns + y_col_outer = np.linspace(0.1, 0.9, 5) # Y-coords for outer 5-circle columns + + count = 0 + # Arrange circles column by column using the staggered y-coordinates + for i in range(5): + x = x_cols[i] + + if i == 2: # Central column (6 circles) + y_coords = y_col_center + elif i == 1 or i == 3: # Inner columns (5 circles), staggered + y_coords = y_col_inner + else: # Outer columns (5 circles), i=0 or i=4 + y_coords = y_col_outer + + for y in y_coords: + centers[count] = [x, y] + count += 1 +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea8b82339455b5b40b446550d89a4f45e0ee0fe6 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..93f4848bd48eac9fc3c51f7cea126b7cca2f150e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/edit.diff @@ -0,0 +1,495 @@ +--- a/original.py ++++ b/original.py +@@ -1,196 +1,367 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" +- + import numpy as np + +-# This function remains the same as it is a robust way to evaluate a given center configuration. +-def compute_max_radii(centers): +- """ +- Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This is +- an iterative version that converges to a stable solution. ++# Utility functions (kept outside classes as they are general calculations) ++def compute_max_radii(centers, max_iterations=500): ++ """ ++ Compute the maximum possible radii for each circle position such that they ++ don't overlap and stay within the unit square. This is an iterative version ++ that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates ++ max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] +- +- # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + +- # Iteratively resolve overlaps between circles until no more changes occur. +- # A high number of iterations ensures convergence for complex arrangements. +- for _ in range(500): # Increased iterations for more thorough convergence ++ for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) +- +- # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] +- if sum_r > 1e-12: # Avoid division by zero +- # Scale both radii down proportionally to resolve the overlap. ++ if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True +- +- # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break +- + return radii + + def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + ++ ++class CirclePackingProblem: ++ """ ++ Encapsulates the definition of the circle packing problem for n circles ++ within a unit square, including initialization, evaluation, and perturbation ++ strategies. ++ """ ++ def __init__(self, n): ++ self.n = n ++ self.centers = None ++ self.radii = None ++ self.sum_radii = 0.0 ++ ++ def _initialize_base_centers(self): ++ """ ++ Initializes circle centers using a Gaussian-deformed grid for 25 circles ++ and places the 26th in an asymmetric void. ++ """ ++ x_coords = np.linspace(0.1, 0.9, 5) ++ y_coords = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords, y_coords) ++ base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T ++ ++ void_center = np.array([0.4, 0.2]) ++ amplitude = 0.06 ++ sigma = 0.15 ++ ++ displacements = base_centers_25 - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ mask = distances > 1e-9 ++ ++ push_magnitudes = np.zeros(25) ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ ++ if np.any(mask): ++ displacements[mask] /= distances[mask, np.newaxis] ++ ++ initial_centers = np.zeros((self.n, 2)) ++ initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ initial_centers[25] = void_center ++ return np.clip(initial_centers, 0.0, 1.0) ++ ++ def _run_force_directed_pre_optimization(self): ++ """ ++ Applies multiple force-directed relaxation configurations and selects ++ the one yielding the highest sum of radii (Recommendation 4). ++ """ ++ initial_base_centers = self._initialize_base_centers() ++ best_pre_opt_centers = initial_base_centers.copy() ++ best_pre_opt_sum_radii = 0.0 ++ ++ # Define multiple parameter sets for F-D relaxation to explore different initial states ++ param_sets = [ ++ # Mild-aggressive ++ {'iterations': 500, 'step_size': 0.001, 'repulsion_strength': 0.01, ++ 'repulsion_threshold': 0.18, 'boundary_strength': 0.05, 'boundary_margin': 0.03}, ++ # More aggressive (from high-performing G169) ++ {'iterations': 800, 'step_size': 0.0015, 'repulsion_strength': 0.015, ++ 'repulsion_threshold': 0.22, 'boundary_strength': 0.08, 'boundary_margin': 0.03}, ++ # Balanced ++ {'iterations': 600, 'step_size': 0.0012, 'repulsion_strength': 0.012, ++ 'repulsion_threshold': 0.20, 'boundary_strength': 0.06, 'boundary_margin': 0.03}, ++ # Slightly denser (reduced repulsion threshold) ++ {'iterations': 700, 'step_size': 0.0013, 'repulsion_strength': 0.011, ++ 'repulsion_threshold': 0.19, 'boundary_strength': 0.055, 'boundary_margin': 0.03}, ++ ] ++ ++ for params in param_sets: ++ relaxed_centers = apply_force_directed_relaxation(initial_base_centers.copy(), **params) ++ radii = compute_max_radii(relaxed_centers) ++ current_sum_radii = np.sum(radii) ++ if current_sum_radii > best_pre_opt_sum_radii: ++ best_pre_opt_sum_radii = current_sum_radii ++ best_pre_opt_centers = relaxed_centers.copy() ++ ++ self.centers = best_pre_opt_centers ++ self.radii = compute_max_radii(self.centers) ++ self.sum_radii = np.sum(self.radii) ++ return self.centers, self.radii, self.sum_radii ++ ++ def _select_circle_for_perturbation(self, current_radii, current_centers): ++ """ ++ Selects a circle to perturb based on its inverse radius, proximity to boundaries, ++ and local crowding (Recommendation 2). ++ """ ++ inverse_radii = 1 / (current_radii + 1e-8) ++ ++ dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], ++ current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) ++ boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) ++ ++ # Local Crowding Metric ++ crowding_metric = np.zeros(self.n) ++ crowding_threshold = 0.25 ++ for i in range(self.n): ++ distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) ++ crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) ++ ++ max_crowding = self.n - 1 ++ normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) ++ crowding_influence_factor = 0.8 ++ ++ combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) ++ selection_probs = combined_weights / np.sum(combined_weights) ++ circle_idx = np.random.choice(self.n, p=selection_probs) ++ return circle_idx ++ ++ def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): ++ """ ++ Calculates an adaptive perturbation strength for a specific circle. ++ Smaller circles receive a proportionally larger perturbation. ++ """ ++ max_r = np.max(current_radii) + 1e-8 ++ relative_radius = current_radii[circle_idx] / max_r ++ perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 ++ return global_perturb_strength * perturb_factor ++ ++ def _generate_neighbor_state(self, current_centers, current_radii, global_perturb_strength, SA_iteration, total_SA_iterations): ++ """ ++ Generates a new candidate state by perturbing one or more circles. ++ Combines single-circle perturbation with multi-modal cluster perturbation (Recommendation 3). ++ """ ++ candidate_centers = current_centers.copy() ++ ++ # Determine adaptive compute_max_radii iterations (Recommendation 5) ++ min_radii_iter = 100 ++ max_radii_iter = 750 ++ current_radii_iterations = int(min_radii_iter + (max_radii_iter - min_radii_iter) * (SA_iteration / total_SA_iterations)) ++ if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration ++ ++ # Multi-modal perturbation choice (Recommendation 3) ++ # With a low probability, perturb a cluster instead of a single circle ++ if np.random.rand() < 0.15: # Increased chance for cluster perturbation to 15% ++ circle_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster ++ ++ all_indices = np.arange(self.n) ++ other_indices = np.delete(all_indices, circle_idx) ++ ++ if len(other_indices) > 0: ++ distances = np.linalg.norm(current_centers[circle_idx] - current_centers[other_indices], axis=1) ++ sorted_neighbor_indices = other_indices[np.argsort(distances)] ++ ++ cluster_indices = [circle_idx] ++ num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors ++ for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): ++ cluster_indices.append(sorted_neighbor_indices[i]) ++ ++ # Apply a coordinated, smaller displacement to the cluster ++ eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) ++ cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move ++ ++ # Generate a single random direction for the entire cluster ++ angle = np.random.uniform(0, 2 * np.pi) ++ direction = np.array([np.cos(angle), np.sin(angle)]) ++ cluster_displacement = cluster_displacement_magnitude * direction ++ ++ for c_idx in cluster_indices: ++ candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) ++ else: # Fallback to single circle if no neighbors for cluster ++ circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) ++ eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) ++ displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) ++ ++ else: # Single circle perturbation (most common case) ++ circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) ++ eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) ++ displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) ++ ++ candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) ++ candidate_sum_radii = np.sum(candidate_radii) ++ ++ return candidate_centers, candidate_radii, candidate_sum_radii ++ ++class SimulatedAnnealingOptimizer: ++ """ ++ Generic Simulated Annealing optimizer. ++ It takes a problem instance that defines initialization, evaluation, ++ and neighbor generation. ++ """ ++ def __init__(self, problem, total_iterations, T_initial, T_final, ++ initial_perturb_base, final_perturb, max_no_improvement_steps, ++ stagnation_boost_duration, stagnation_aggressive_perturb_multiplier): ++ ++ self.problem = problem ++ self.total_iterations = total_iterations ++ self.T_initial = T_initial ++ self.T_final = T_final ++ self.initial_perturb_base = initial_perturb_base ++ self.final_perturb = final_perturb ++ self.max_no_improvement_steps = max_no_improvement_steps ++ self.stagnation_boost_duration = stagnation_boost_duration ++ self.stagnation_aggressive_perturb_multiplier = stagnation_aggressive_perturb_multiplier ++ ++ self.best_centers = None ++ self.best_radii = None ++ self.best_sum_radii = -np.inf ++ ++ def run(self): ++ """ ++ Executes the Simulated Annealing process. ++ """ ++ # Initial state from the problem's pre-optimization ++ current_centers, current_radii, current_sum_radii = self.problem.centers, self.problem.radii, self.problem.sum_radii ++ ++ self.best_centers = current_centers.copy() ++ self.best_radii = current_radii.copy() ++ self.best_sum_radii = current_sum_radii ++ ++ no_improvement_count = 0 ++ current_initial_perturb = self.initial_perturb_base ++ stagnation_boost_active_counter = 0 ++ ++ for iteration in range(self.total_iterations): ++ # Annealing schedules ++ global_perturb_strength = current_initial_perturb * (1 - iteration / self.total_iterations) + self.final_perturb * (iteration / self.total_iterations) ++ ++ # Apply temporary aggressive perturbation if in stagnation escape (Recommendation 1) ++ if stagnation_boost_active_counter > 0: ++ global_perturb_strength *= self.stagnation_aggressive_perturb_multiplier ++ stagnation_boost_active_counter -= 1 ++ ++ temperature = self.T_initial * (self.T_final / self.T_initial)**(iteration / self.total_iterations) ++ ++ # Generate candidate state using problem's specific method ++ candidate_centers, candidate_radii, candidate_sum_radii = self.problem._generate_neighbor_state( ++ current_centers, current_radii, global_perturb_strength, iteration, self.total_iterations ++ ) ++ ++ # Simulated Annealing acceptance criteria ++ accepted = False ++ if candidate_sum_radii > current_sum_radii: ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers.copy() ++ current_radii = candidate_radii.copy() ++ accepted = True ++ else: ++ delta = candidate_sum_radii - current_sum_radii ++ acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 ++ if np.random.rand() < acceptance_prob: ++ current_sum_radii = candidate_sum_radii ++ current_centers = candidate_centers.copy() ++ current_radii = candidate_radii.copy() ++ accepted = True ++ ++ # Update best solution and manage stagnation (Recommendation 1) ++ if current_sum_radii > self.best_sum_radii: ++ self.best_sum_radii = current_sum_radii ++ self.best_centers = current_centers.copy() ++ self.best_radii = current_radii.copy() ++ no_improvement_count = 0 ++ elif not accepted: ++ no_improvement_count += 1 ++ if no_improvement_count > self.max_no_improvement_steps: ++ current_initial_perturb *= 1.1 # Small permanent boost to exploration potential ++ stagnation_boost_active_counter = self.stagnation_boost_duration # Activate temporary aggressive boost ++ no_improvement_count = 0 ++ ++ return self.best_centers, self.best_radii ++ ++ + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles. This method combines +- a proven asymmetric initialization, a mild force-directed pre-relaxation, +- and a sophisticated Simulated Annealing local search with adaptive heuristics. +- """ +- n = 26 +- +- # 1. Initialization: Asymmetric Gaussian-deformed grid. +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T +- void_center = np.array([0.4, 0.2]) +- amplitude, sigma = 0.06, 0.15 +- +- displacements = base_centers_25 - void_center +- distances = np.linalg.norm(displacements, axis=1) +- mask = distances > 1e-9 +- push_magnitudes = np.zeros(25) +- push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) +- displacements[mask] /= distances[mask, np.newaxis] +- +- centers = np.zeros((n, 2)) +- centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- centers[25] = void_center +- centers = np.clip(centers, 0.0, 1.0) +- +- # 2. Pre-optimization: A mild force-directed relaxation to settle the initial state. +- centers = apply_force_directed_relaxation( +- centers, iterations=500, step_size=0.001, repulsion_strength=0.01, +- repulsion_threshold=0.18, boundary_strength=0.05, boundary_margin=0.03 +- ) +- +- # 3. Main Optimization: Advanced Simulated Annealing with Stagnation Escape. +- radii = compute_max_radii(centers) +- +- best_centers = centers.copy() +- best_radii = radii.copy() +- best_sum_radii = np.sum(radii) +- +- current_centers = centers.copy() +- current_radii = radii.copy() +- current_sum_radii = best_sum_radii +- +- # Tuned SA parameters based on high-performing ancestors for better exploration +- total_iterations = 15000 +- initial_g_perturb_base = 0.04 +- final_g_perturb = 0.0003 +- T_initial, T_final = 0.2, 1e-7 +- +- # Stagnation escape mechanism to kick search out of local optima +- no_improvement_count = 0 +- max_no_improvement_steps = 500 +- current_initial_g_perturb = initial_g_perturb_base +- +- for it in range(total_iterations): +- # Annealing schedules with dynamic perturbation +- g_perturb = current_initial_g_perturb + (final_g_perturb - current_initial_g_perturb) * (it / total_iterations) +- temp = T_initial * (T_final / T_initial)**(it / total_iterations) +- +- candidate_centers = current_centers.copy() +- +- # Adaptive Selection: Prioritize small circles and those near boundaries +- inverse_radii = 1 / (current_radii + 1e-8) +- dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0) +- boundary_weight = np.exp(-dist_to_boundary / 0.1) +- weights = inverse_radii * (1 + boundary_weight) +- probs = weights / np.sum(weights) +- circle_idx = np.random.choice(n, p=probs) +- +- # Adaptive Perturbation: Give larger kicks to smaller circles +- max_r = np.max(current_radii) + 1e-8 +- relative_r = current_radii[circle_idx] / max_r +- # Increased multiplier for more aggressive small circle movement +- perturb_factor = 1.0 + (1.0 - relative_r) * 2.0 +- eff_perturb = g_perturb * perturb_factor +- +- displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) +- +- # Evaluation and Acceptance +- candidate_radii = compute_max_radii(candidate_centers) +- candidate_sum_radii = np.sum(candidate_radii) +- +- accepted = False +- delta = candidate_sum_radii - current_sum_radii +- if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): +- current_sum_radii = candidate_sum_radii +- current_centers = candidate_centers.copy() +- current_radii = candidate_radii.copy() +- accepted = True +- +- # Update best solution and manage stagnation +- if current_sum_radii > best_sum_radii: +- best_sum_radii = current_sum_radii +- best_centers = current_centers.copy() +- best_radii = current_radii.copy() +- no_improvement_count = 0 # Reset on new best +- elif not accepted: +- no_improvement_count += 1 +- # If stagnated, boost perturbation to escape local optimum +- if no_improvement_count > max_no_improvement_steps: +- current_initial_g_perturb *= 1.2 +- no_improvement_count = 0 +- +- return best_centers, best_radii ++ Main function to construct the circle packing. ++ Initializes CirclePackingProblem and runs SimulatedAnnealingOptimizer. ++ """ ++ n_circles = 26 ++ problem = CirclePackingProblem(n_circles) ++ ++ # Pre-optimization phase (Recommendation 4) ++ # This sets problem.centers, problem.radii, problem.sum_radii ++ problem._run_force_directed_pre_optimization() ++ ++ # Simulated Annealing parameters ++ sa_params = { ++ 'total_iterations': 25000, ++ 'T_initial': 0.4, ++ 'T_final': 1e-9, ++ 'initial_perturb_base': 0.06, ++ 'final_perturb': 0.0001, ++ 'max_no_improvement_steps': 1000, ++ 'stagnation_boost_duration': 200, ++ 'stagnation_aggressive_perturb_multiplier': 2.0 ++ } ++ ++ optimizer = SimulatedAnnealingOptimizer(problem, **sa_params) ++ return optimizer.run() ++ + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/main.py new file mode 100644 index 0000000000000000000000000000000000000000..a9e00878b90e1ac9653142eaaa1af28c2bbce51a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/main.py @@ -0,0 +1,367 @@ +# EVOLVE-BLOCK-START +import numpy as np + +# Utility functions (kept outside classes as they are general calculations) +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + +class CirclePackingProblem: + """ + Encapsulates the definition of the circle packing problem for n circles + within a unit square, including initialization, evaluation, and perturbation + strategies. + """ + def __init__(self, n): + self.n = n + self.centers = None + self.radii = None + self.sum_radii = 0.0 + + def _initialize_base_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + def _run_force_directed_pre_optimization(self): + """ + Applies multiple force-directed relaxation configurations and selects + the one yielding the highest sum of radii (Recommendation 4). + """ + initial_base_centers = self._initialize_base_centers() + best_pre_opt_centers = initial_base_centers.copy() + best_pre_opt_sum_radii = 0.0 + + # Define multiple parameter sets for F-D relaxation to explore different initial states + param_sets = [ + # Mild-aggressive + {'iterations': 500, 'step_size': 0.001, 'repulsion_strength': 0.01, + 'repulsion_threshold': 0.18, 'boundary_strength': 0.05, 'boundary_margin': 0.03}, + # More aggressive (from high-performing G169) + {'iterations': 800, 'step_size': 0.0015, 'repulsion_strength': 0.015, + 'repulsion_threshold': 0.22, 'boundary_strength': 0.08, 'boundary_margin': 0.03}, + # Balanced + {'iterations': 600, 'step_size': 0.0012, 'repulsion_strength': 0.012, + 'repulsion_threshold': 0.20, 'boundary_strength': 0.06, 'boundary_margin': 0.03}, + # Slightly denser (reduced repulsion threshold) + {'iterations': 700, 'step_size': 0.0013, 'repulsion_strength': 0.011, + 'repulsion_threshold': 0.19, 'boundary_strength': 0.055, 'boundary_margin': 0.03}, + ] + + for params in param_sets: + relaxed_centers = apply_force_directed_relaxation(initial_base_centers.copy(), **params) + radii = compute_max_radii(relaxed_centers) + current_sum_radii = np.sum(radii) + if current_sum_radii > best_pre_opt_sum_radii: + best_pre_opt_sum_radii = current_sum_radii + best_pre_opt_centers = relaxed_centers.copy() + + self.centers = best_pre_opt_centers + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + return self.centers, self.radii, self.sum_radii + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding (Recommendation 2). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 + + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation. + """ + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 + return global_perturb_strength * perturb_factor + + def _generate_neighbor_state(self, current_centers, current_radii, global_perturb_strength, SA_iteration, total_SA_iterations): + """ + Generates a new candidate state by perturbing one or more circles. + Combines single-circle perturbation with multi-modal cluster perturbation (Recommendation 3). + """ + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (Recommendation 5) + min_radii_iter = 100 + max_radii_iter = 750 + current_radii_iterations = int(min_radii_iter + (max_radii_iter - min_radii_iter) * (SA_iteration / total_SA_iterations)) + if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration + + # Multi-modal perturbation choice (Recommendation 3) + # With a low probability, perturb a cluster instead of a single circle + if np.random.rand() < 0.15: # Increased chance for cluster perturbation to 15% + circle_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster + + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, circle_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[circle_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [circle_idx] + num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + # Apply a coordinated, smaller displacement to the cluster + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move + + # Generate a single random direction for the entire cluster + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([np.cos(angle), np.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle if no neighbors for cluster + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + return candidate_centers, candidate_radii, candidate_sum_radii + +class SimulatedAnnealingOptimizer: + """ + Generic Simulated Annealing optimizer. + It takes a problem instance that defines initialization, evaluation, + and neighbor generation. + """ + def __init__(self, problem, total_iterations, T_initial, T_final, + initial_perturb_base, final_perturb, max_no_improvement_steps, + stagnation_boost_duration, stagnation_aggressive_perturb_multiplier): + + self.problem = problem + self.total_iterations = total_iterations + self.T_initial = T_initial + self.T_final = T_final + self.initial_perturb_base = initial_perturb_base + self.final_perturb = final_perturb + self.max_no_improvement_steps = max_no_improvement_steps + self.stagnation_boost_duration = stagnation_boost_duration + self.stagnation_aggressive_perturb_multiplier = stagnation_aggressive_perturb_multiplier + + self.best_centers = None + self.best_radii = None + self.best_sum_radii = -np.inf + + def run(self): + """ + Executes the Simulated Annealing process. + """ + # Initial state from the problem's pre-optimization + current_centers, current_radii, current_sum_radii = self.problem.centers, self.problem.radii, self.problem.sum_radii + + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + self.best_sum_radii = current_sum_radii + + no_improvement_count = 0 + current_initial_perturb = self.initial_perturb_base + stagnation_boost_active_counter = 0 + + for iteration in range(self.total_iterations): + # Annealing schedules + global_perturb_strength = current_initial_perturb * (1 - iteration / self.total_iterations) + self.final_perturb * (iteration / self.total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape (Recommendation 1) + if stagnation_boost_active_counter > 0: + global_perturb_strength *= self.stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + temperature = self.T_initial * (self.T_final / self.T_initial)**(iteration / self.total_iterations) + + # Generate candidate state using problem's specific method + candidate_centers, candidate_radii, candidate_sum_radii = self.problem._generate_neighbor_state( + current_centers, current_radii, global_perturb_strength, iteration, self.total_iterations + ) + + # Simulated Annealing acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + delta = candidate_sum_radii - current_sum_radii + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation (Recommendation 1) + if current_sum_radii > self.best_sum_radii: + self.best_sum_radii = current_sum_radii + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + no_improvement_count = 0 + elif not accepted: + no_improvement_count += 1 + if no_improvement_count > self.max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential + stagnation_boost_active_counter = self.stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return self.best_centers, self.best_radii + + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePackingProblem and runs SimulatedAnnealingOptimizer. + """ + n_circles = 26 + problem = CirclePackingProblem(n_circles) + + # Pre-optimization phase (Recommendation 4) + # This sets problem.centers, problem.radii, problem.sum_radii + problem._run_force_directed_pre_optimization() + + # Simulated Annealing parameters + sa_params = { + 'total_iterations': 25000, + 'T_initial': 0.4, + 'T_final': 1e-9, + 'initial_perturb_base': 0.06, + 'final_perturb': 0.0001, + 'max_no_improvement_steps': 1000, + 'stagnation_boost_duration': 200, + 'stagnation_aggressive_perturb_multiplier': 2.0 + } + + optimizer = SimulatedAnnealingOptimizer(problem, **sa_params) + return optimizer.run() + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/original.py new file mode 100644 index 0000000000000000000000000000000000000000..4509aa908510836880878b833c5f66a3fa184d75 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/original.py @@ -0,0 +1,196 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + +# This function remains the same as it is a robust way to evaluate a given center configuration. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + # Scale both radii down proportionally to resolve the overlap. + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles. This method combines + a proven asymmetric initialization, a mild force-directed pre-relaxation, + and a sophisticated Simulated Annealing local search with adaptive heuristics. + """ + n = 26 + + # 1. Initialization: Asymmetric Gaussian-deformed grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + void_center = np.array([0.4, 0.2]) + amplitude, sigma = 0.06, 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + centers = np.zeros((n, 2)) + centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 2. Pre-optimization: A mild force-directed relaxation to settle the initial state. + centers = apply_force_directed_relaxation( + centers, iterations=500, step_size=0.001, repulsion_strength=0.01, + repulsion_threshold=0.18, boundary_strength=0.05, boundary_margin=0.03 + ) + + # 3. Main Optimization: Advanced Simulated Annealing with Stagnation Escape. + radii = compute_max_radii(centers) + + best_centers = centers.copy() + best_radii = radii.copy() + best_sum_radii = np.sum(radii) + + current_centers = centers.copy() + current_radii = radii.copy() + current_sum_radii = best_sum_radii + + # Tuned SA parameters based on high-performing ancestors for better exploration + total_iterations = 15000 + initial_g_perturb_base = 0.04 + final_g_perturb = 0.0003 + T_initial, T_final = 0.2, 1e-7 + + # Stagnation escape mechanism to kick search out of local optima + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_g_perturb = initial_g_perturb_base + + for it in range(total_iterations): + # Annealing schedules with dynamic perturbation + g_perturb = current_initial_g_perturb + (final_g_perturb - current_initial_g_perturb) * (it / total_iterations) + temp = T_initial * (T_final / T_initial)**(it / total_iterations) + + candidate_centers = current_centers.copy() + + # Adaptive Selection: Prioritize small circles and those near boundaries + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([candidate_centers[:, 0], 1 - candidate_centers[:, 0], candidate_centers[:, 1], 1 - candidate_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.1) + weights = inverse_radii * (1 + boundary_weight) + probs = weights / np.sum(weights) + circle_idx = np.random.choice(n, p=probs) + + # Adaptive Perturbation: Give larger kicks to smaller circles + max_r = np.max(current_radii) + 1e-8 + relative_r = current_radii[circle_idx] / max_r + # Increased multiplier for more aggressive small circle movement + perturb_factor = 1.0 + (1.0 - relative_r) * 2.0 + eff_perturb = g_perturb * perturb_factor + + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluation and Acceptance + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + accepted = False + delta = candidate_sum_radii - current_sum_radii + if delta > 0 or (temp > 0 and np.random.rand() < np.exp(delta / temp)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best + elif not accepted: + no_improvement_count += 1 + # If stagnated, boost perturbation to escape local optimum + if no_improvement_count > max_no_improvement_steps: + current_initial_g_perturb *= 1.2 + no_improvement_count = 0 + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..51dcd3416626bb10ffa2878ff4d0ef980461b131 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_180/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_180/results +Run 1/1 completed in 67.47 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.332906296277705 + public: {'centers_str': ' centers[0] = (0.3846, 0.3104)\n centers[1] = (0.6692, 0.5264)\n centers[2] = (0.7529, 0.8983)\n centers[3] = (0.2621, 0.6763)\n centers[4] = (0.2018, 0.0520)\n centers[5] = (0.6723, 0.1003)\n centers[6] = (0.9208, 0.9320)\n centers[7] = (0.5703, 0.4215)\n centers[8] = (0.3495, 0.1053)\n centers[9] = (0.9456, 0.8120)\n centers[10] = (0.5402, 0.7146)\n centers[11] = (0.0633, 0.3638)\n centers[12] = (0.9298, 0.4450)\n centers[13] = (0.0679, 0.2321)\n centers[14] = (0.0774, 0.0873)\n centers[15] = (0.8851, 0.1312)\n centers[16] = (0.3876, 0.8800)\n centers[17] = (0.5151, 0.2500)\n centers[18] = (0.2450, 0.3112)\n centers[19] = (0.5696, 0.9175)\n centers[20] = (0.4007, 0.5093)\n centers[21] = (0.1362, 0.8639)\n centers[22] = (0.7441, 0.3551)\n centers[23] = (0.8133, 0.6435)\n centers[24] = (0.9348, 0.3060)\n centers[25] = (0.1147, 0.5344)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.332906296277705} + visualization_path: + execution_time_mean: 67.47335524763912 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..ba031b1c1b478bcf92cd2ce78fef4b24b609269f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.332906296277705, + "public": { + "centers_str": " centers[0] = (0.3846, 0.3104)\n centers[1] = (0.6692, 0.5264)\n centers[2] = (0.7529, 0.8983)\n centers[3] = (0.2621, 0.6763)\n centers[4] = (0.2018, 0.0520)\n centers[5] = (0.6723, 0.1003)\n centers[6] = (0.9208, 0.9320)\n centers[7] = (0.5703, 0.4215)\n centers[8] = (0.3495, 0.1053)\n centers[9] = (0.9456, 0.8120)\n centers[10] = (0.5402, 0.7146)\n centers[11] = (0.0633, 0.3638)\n centers[12] = (0.9298, 0.4450)\n centers[13] = (0.0679, 0.2321)\n centers[14] = (0.0774, 0.0873)\n centers[15] = (0.8851, 0.1312)\n centers[16] = (0.3876, 0.8800)\n centers[17] = (0.5151, 0.2500)\n centers[18] = (0.2450, 0.3112)\n centers[19] = (0.5696, 0.9175)\n centers[20] = (0.4007, 0.5093)\n centers[21] = (0.1362, 0.8639)\n centers[22] = (0.7441, 0.3551)\n centers[23] = (0.8133, 0.6435)\n centers[24] = (0.9348, 0.3060)\n centers[25] = (0.1147, 0.5344)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.332906296277705 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_180/results/packing_viz.png", + "execution_time_mean": 67.47335524763912, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..a9e00878b90e1ac9653142eaaa1af28c2bbce51a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_180/rewrite.txt @@ -0,0 +1,367 @@ +# EVOLVE-BLOCK-START +import numpy as np + +# Utility functions (kept outside classes as they are general calculations) +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + +class CirclePackingProblem: + """ + Encapsulates the definition of the circle packing problem for n circles + within a unit square, including initialization, evaluation, and perturbation + strategies. + """ + def __init__(self, n): + self.n = n + self.centers = None + self.radii = None + self.sum_radii = 0.0 + + def _initialize_base_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + def _run_force_directed_pre_optimization(self): + """ + Applies multiple force-directed relaxation configurations and selects + the one yielding the highest sum of radii (Recommendation 4). + """ + initial_base_centers = self._initialize_base_centers() + best_pre_opt_centers = initial_base_centers.copy() + best_pre_opt_sum_radii = 0.0 + + # Define multiple parameter sets for F-D relaxation to explore different initial states + param_sets = [ + # Mild-aggressive + {'iterations': 500, 'step_size': 0.001, 'repulsion_strength': 0.01, + 'repulsion_threshold': 0.18, 'boundary_strength': 0.05, 'boundary_margin': 0.03}, + # More aggressive (from high-performing G169) + {'iterations': 800, 'step_size': 0.0015, 'repulsion_strength': 0.015, + 'repulsion_threshold': 0.22, 'boundary_strength': 0.08, 'boundary_margin': 0.03}, + # Balanced + {'iterations': 600, 'step_size': 0.0012, 'repulsion_strength': 0.012, + 'repulsion_threshold': 0.20, 'boundary_strength': 0.06, 'boundary_margin': 0.03}, + # Slightly denser (reduced repulsion threshold) + {'iterations': 700, 'step_size': 0.0013, 'repulsion_strength': 0.011, + 'repulsion_threshold': 0.19, 'boundary_strength': 0.055, 'boundary_margin': 0.03}, + ] + + for params in param_sets: + relaxed_centers = apply_force_directed_relaxation(initial_base_centers.copy(), **params) + radii = compute_max_radii(relaxed_centers) + current_sum_radii = np.sum(radii) + if current_sum_radii > best_pre_opt_sum_radii: + best_pre_opt_sum_radii = current_sum_radii + best_pre_opt_centers = relaxed_centers.copy() + + self.centers = best_pre_opt_centers + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + return self.centers, self.radii, self.sum_radii + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding (Recommendation 2). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 + + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation. + """ + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 + return global_perturb_strength * perturb_factor + + def _generate_neighbor_state(self, current_centers, current_radii, global_perturb_strength, SA_iteration, total_SA_iterations): + """ + Generates a new candidate state by perturbing one or more circles. + Combines single-circle perturbation with multi-modal cluster perturbation (Recommendation 3). + """ + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (Recommendation 5) + min_radii_iter = 100 + max_radii_iter = 750 + current_radii_iterations = int(min_radii_iter + (max_radii_iter - min_radii_iter) * (SA_iteration / total_SA_iterations)) + if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration + + # Multi-modal perturbation choice (Recommendation 3) + # With a low probability, perturb a cluster instead of a single circle + if np.random.rand() < 0.15: # Increased chance for cluster perturbation to 15% + circle_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster + + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, circle_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[circle_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [circle_idx] + num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + # Apply a coordinated, smaller displacement to the cluster + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move + + # Generate a single random direction for the entire cluster + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([np.cos(angle), np.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle if no neighbors for cluster + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + return candidate_centers, candidate_radii, candidate_sum_radii + +class SimulatedAnnealingOptimizer: + """ + Generic Simulated Annealing optimizer. + It takes a problem instance that defines initialization, evaluation, + and neighbor generation. + """ + def __init__(self, problem, total_iterations, T_initial, T_final, + initial_perturb_base, final_perturb, max_no_improvement_steps, + stagnation_boost_duration, stagnation_aggressive_perturb_multiplier): + + self.problem = problem + self.total_iterations = total_iterations + self.T_initial = T_initial + self.T_final = T_final + self.initial_perturb_base = initial_perturb_base + self.final_perturb = final_perturb + self.max_no_improvement_steps = max_no_improvement_steps + self.stagnation_boost_duration = stagnation_boost_duration + self.stagnation_aggressive_perturb_multiplier = stagnation_aggressive_perturb_multiplier + + self.best_centers = None + self.best_radii = None + self.best_sum_radii = -np.inf + + def run(self): + """ + Executes the Simulated Annealing process. + """ + # Initial state from the problem's pre-optimization + current_centers, current_radii, current_sum_radii = self.problem.centers, self.problem.radii, self.problem.sum_radii + + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + self.best_sum_radii = current_sum_radii + + no_improvement_count = 0 + current_initial_perturb = self.initial_perturb_base + stagnation_boost_active_counter = 0 + + for iteration in range(self.total_iterations): + # Annealing schedules + global_perturb_strength = current_initial_perturb * (1 - iteration / self.total_iterations) + self.final_perturb * (iteration / self.total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape (Recommendation 1) + if stagnation_boost_active_counter > 0: + global_perturb_strength *= self.stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + temperature = self.T_initial * (self.T_final / self.T_initial)**(iteration / self.total_iterations) + + # Generate candidate state using problem's specific method + candidate_centers, candidate_radii, candidate_sum_radii = self.problem._generate_neighbor_state( + current_centers, current_radii, global_perturb_strength, iteration, self.total_iterations + ) + + # Simulated Annealing acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + delta = candidate_sum_radii - current_sum_radii + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation (Recommendation 1) + if current_sum_radii > self.best_sum_radii: + self.best_sum_radii = current_sum_radii + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + no_improvement_count = 0 + elif not accepted: + no_improvement_count += 1 + if no_improvement_count > self.max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential + stagnation_boost_active_counter = self.stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return self.best_centers, self.best_radii + + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePackingProblem and runs SimulatedAnnealingOptimizer. + """ + n_circles = 26 + problem = CirclePackingProblem(n_circles) + + # Pre-optimization phase (Recommendation 4) + # This sets problem.centers, problem.radii, problem.sum_radii + problem._run_force_directed_pre_optimization() + + # Simulated Annealing parameters + sa_params = { + 'total_iterations': 25000, + 'T_initial': 0.4, + 'T_final': 1e-9, + 'initial_perturb_base': 0.06, + 'final_perturb': 0.0001, + 'max_no_improvement_steps': 1000, + 'stagnation_boost_duration': 200, + 'stagnation_aggressive_perturb_multiplier': 2.0 + } + + optimizer = SimulatedAnnealingOptimizer(problem, **sa_params) + return optimizer.run() + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dba983504f4b31d08cfa4b8debc1b2b654f59765 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..6ee360e4b9552f19da9254a132058f269e2a8024 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/edit.diff @@ -0,0 +1,381 @@ +--- a/original.py ++++ b/original.py +@@ -1,320 +1,332 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + + # compute_max_radii remains unchanged as it's a robust evaluation function. + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + + class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] # (N, N, 2) + dists = np.linalg.norm(diff, axis=2) # (N, N) + + # Mask out self-interaction by setting diagonal distances to a very large value + np.fill_diagonal(dists, np.inf) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors F_ij (force on i from j) + # F_ij direction is (centers[i] - centers[j]) / dists[i,j] + # Store unit vectors: normalized_diff[i,j] = (centers[i] - centers[j]) / dists[i,j] + normalized_diff = np.zeros_like(diff) + # Avoid division by zero where dists might be zero or inf (already handled diag to inf) + # The where clause ensures division only happens for valid non-zero distances. + # This covers the repulsion_mask values which are > 1e-9. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # Sum force_magnitudes[i,j] * normalized_diff[i,j] over j for each i + # This correctly sums F_ij (force exerted by j on i) for all j!=i + forces_repulsion = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + forces += forces_repulsion + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability +- to escape local optima. ++ to escape local optima, incorporating multi-modal perturbations. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + +- cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation +- +- # Stagnation detection and escape parameters ++ # Perturbation strategy probabilities ++ swap_perturb_prob = 0.15 # Probability of performing a small-large circle swap ++ cluster_perturb_prob = 0.1 # Probability of performing a clustered perturbation ++ single_perturb_prob = 1.0 - swap_perturb_prob - cluster_perturb_prob # Remainder for single circle move ++ ++ # Stagnation detection and escape parameters (aligned with higher performing versions) + stagnation_counter = 0 +- stagnation_threshold = 1000 # Iterations without finding a new best to trigger a boost ++ stagnation_threshold = 1200 # Iterations without finding a new best to trigger a boost + perturb_boost = 1.0 +- boost_factor = 3.0 # A strong, but not excessively disruptive, kick +- boost_decay = 0.97 # Gradual decay of the boost ++ boost_factor = 3.5 # Stronger kick ++ boost_decay = 0.96 # Slightly faster decay ++ temp_reheat_factor_on_stagnation = 0.6 # More significant reheating + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations +- temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) ++ temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + +- # Check for stagnation and apply a temporary perturbation boost ++ current_temp = temp_schedule # Use the scheduled temperature by default ++ ++ # Check for stagnation and apply a temporary perturbation boost and temperature reheat + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor ++ current_temp = temp_schedule + initial_temp * temp_reheat_factor_on_stagnation # Reheat temperature + stagnation_counter = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() +- +- # Target smaller circles for perturbation to help them grow and rearrange +- # Add small constant to avoid div by zero, and ensure it's calculated from current_radii +- inverse_radii = 1 / (current_radii + 1e-8) +- selection_probs = inverse_radii / np.sum(inverse_radii) +- +- # --- Clustered or Single Circle Perturbation --- +- if np.random.rand() < cluster_perturb_prob: +- # Clustered perturbation: select a primary circle, then its nearest neighbors +- primary_idx = np.random.choice(self.n, p=selection_probs) +- +- # Find the 2 closest neighbors (excluding self) ++ rand_val = np.random.rand() ++ ++ if rand_val < swap_perturb_prob: ++ # Type 1: Swap Perturbation ++ sorted_indices = np.argsort(current_radii) ++ if self.n > 1: ++ num_small_candidates = max(1, self.n // 4) # Consider top 25% smallest ++ num_large_candidates = max(1, self.n // 4) # Consider top 25% largest ++ ++ small_circles_indices = sorted_indices[:num_small_candidates] ++ large_circles_indices = sorted_indices[-num_large_candidates:] ++ ++ if len(small_circles_indices) > 0 and len(large_circles_indices) > 0: ++ idx_small = np.random.choice(small_circles_indices) ++ idx_large = np.random.choice(large_circles_indices) ++ ++ # Swap positions ++ candidate_centers[idx_small], candidate_centers[idx_large] = \ ++ candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() ++ elif rand_val < swap_perturb_prob + cluster_perturb_prob: ++ # Type 2: Clustered Perturbation ++ # Select a primary circle using the full context-aware selection ++ primary_idx = self._select_circle_for_perturbation(current_radii, current_centers) ++ ++ # Find its 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) +- # Use argsort to get indices of circles sorted by distance +- # Skip the first element which is the primary_idx itself (distance 0) +- neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors ++ distances_to_primary[primary_idx] = np.inf # Exclude self from being its own neighbor ++ neighbor_indices = np.argsort(distances_to_primary)[:2] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + +- # Calculate adaptive perturbation strength based on the primary circle's inverse radius +- avg_inverse_radius = np.mean(inverse_radii) +- scale_factor = inverse_radii[primary_idx] / avg_inverse_radius +- # Clamp the scale factor to prevent excessively large or small perturbations. +- effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost +- +- # Generate a single displacement vector for the entire cluster +- displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) ++ # Calculate effective perturbation for the cluster (scaled down compared to single circle) ++ # Use adaptive perturbation strength based on primary_idx's radius, then scale for cluster ++ effective_perturb_strength = self._adaptive_perturbation(base_perturb_strength, primary_idx, current_radii) * perturb_boost ++ cluster_move_strength = effective_perturb_strength * 0.7 # Cluster moves are generally smaller ++ ++ displacement = np.random.uniform(-cluster_move_strength, cluster_move_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: +- # Single circle perturbation +- circle_idx = np.random.choice(self.n, p=selection_probs) +- +- # Apply adaptive perturbation strength based on the selected circle's inverse radius +- avg_inverse_radius = np.mean(inverse_radii) +- scale_factor = inverse_radii[circle_idx] / avg_inverse_radius +- effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost +- +- # Apply a random displacement ++ # Type 3: Single Circle Displacement (most common perturbation) ++ circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) ++ effective_perturb_strength = self._adaptive_perturbation(base_perturb_strength, circle_idx, current_radii) * perturb_boost ++ + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better +- if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): ++ if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + stagnation_counter = 0 # Reset on new best + else: + stagnation_counter += 1 # Increment on accepted but not better + else: + stagnation_counter += 1 # Increment on reject + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( +- total_iterations=20000, # Increased iterations to support more thorough search with stagnation escape +- initial_temp=0.0007, # Slightly higher initial temp +- final_temp=1e-9, # Slightly lower final temp +- initial_perturb_strength=0.03, # Slightly larger initial perturbation ++ total_iterations=35000, # Increased iterations for more thorough search ++ initial_temp=0.0008, # Slightly adjusted initial temp ++ final_temp=1e-10, # Slightly lower final temp ++ initial_perturb_strength=0.035, # Slightly adjusted initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/main.py new file mode 100644 index 0000000000000000000000000000000000000000..9b1d3ed1d498b825e1650b0159ac6929c96abd31 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/main.py @@ -0,0 +1,332 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] # (N, N, 2) + dists = np.linalg.norm(diff, axis=2) # (N, N) + + # Mask out self-interaction by setting diagonal distances to a very large value + np.fill_diagonal(dists, np.inf) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors F_ij (force on i from j) + # F_ij direction is (centers[i] - centers[j]) / dists[i,j] + # Store unit vectors: normalized_diff[i,j] = (centers[i] - centers[j]) / dists[i,j] + normalized_diff = np.zeros_like(diff) + # Avoid division by zero where dists might be zero or inf (already handled diag to inf) + # The where clause ensures division only happens for valid non-zero distances. + # This covers the repulsion_mask values which are > 1e-9. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # Sum force_magnitudes[i,j] * normalized_diff[i,j] over j for each i + # This correctly sums F_ij (force exerted by j on i) for all j!=i + forces_repulsion = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + forces += forces_repulsion + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima, incorporating multi-modal perturbations. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Perturbation strategy probabilities + swap_perturb_prob = 0.15 # Probability of performing a small-large circle swap + cluster_perturb_prob = 0.1 # Probability of performing a clustered perturbation + single_perturb_prob = 1.0 - swap_perturb_prob - cluster_perturb_prob # Remainder for single circle move + + # Stagnation detection and escape parameters (aligned with higher performing versions) + stagnation_counter = 0 + stagnation_threshold = 1200 # Iterations without finding a new best to trigger a boost + perturb_boost = 1.0 + boost_factor = 3.5 # Stronger kick + boost_decay = 0.96 # Slightly faster decay + temp_reheat_factor_on_stagnation = 0.6 # More significant reheating + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + current_temp = temp_schedule # Use the scheduled temperature by default + + # Check for stagnation and apply a temporary perturbation boost and temperature reheat + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp = temp_schedule + initial_temp * temp_reheat_factor_on_stagnation # Reheat temperature + stagnation_counter = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_perturb_prob: + # Type 1: Swap Perturbation + sorted_indices = np.argsort(current_radii) + if self.n > 1: + num_small_candidates = max(1, self.n // 4) # Consider top 25% smallest + num_large_candidates = max(1, self.n // 4) # Consider top 25% largest + + small_circles_indices = sorted_indices[:num_small_candidates] + large_circles_indices = sorted_indices[-num_large_candidates:] + + if len(small_circles_indices) > 0 and len(large_circles_indices) > 0: + idx_small = np.random.choice(small_circles_indices) + idx_large = np.random.choice(large_circles_indices) + + # Swap positions + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() + elif rand_val < swap_perturb_prob + cluster_perturb_prob: + # Type 2: Clustered Perturbation + # Select a primary circle using the full context-aware selection + primary_idx = self._select_circle_for_perturbation(current_radii, current_centers) + + # Find its 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances_to_primary[primary_idx] = np.inf # Exclude self from being its own neighbor + neighbor_indices = np.argsort(distances_to_primary)[:2] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate effective perturbation for the cluster (scaled down compared to single circle) + # Use adaptive perturbation strength based on primary_idx's radius, then scale for cluster + effective_perturb_strength = self._adaptive_perturbation(base_perturb_strength, primary_idx, current_radii) * perturb_boost + cluster_move_strength = effective_perturb_strength * 0.7 # Cluster moves are generally smaller + + displacement = np.random.uniform(-cluster_move_strength, cluster_move_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Type 3: Single Circle Displacement (most common perturbation) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + effective_perturb_strength = self._adaptive_perturbation(base_perturb_strength, circle_idx, current_radii) * perturb_boost + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + stagnation_counter = 0 # Reset on new best + else: + stagnation_counter += 1 # Increment on accepted but not better + else: + stagnation_counter += 1 # Increment on reject + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( + total_iterations=35000, # Increased iterations for more thorough search + initial_temp=0.0008, # Slightly adjusted initial temp + final_temp=1e-10, # Slightly lower final temp + initial_perturb_strength=0.035, # Slightly adjusted initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/original.py new file mode 100644 index 0000000000000000000000000000000000000000..c3080177233d6a809bf2ef2a8defc37b75073deb --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/original.py @@ -0,0 +1,320 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +# compute_max_radii remains unchanged as it's a robust evaluation function. +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): # Increased iterations for more thorough convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the state and logic for packing circles using + a hybrid approach: initial aggressive perturbation, a quick force-directed + relaxation, and then a primary optimization via simulated annealing. + + This structure aims to combine the benefits of force-directed methods + (quick stabilization) with metaheuristics (escaping local optima). + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void_and_perturbation(self, void_center, amplitude, sigma): + """ + Generates an initial configuration by creating a base 5x5 grid, + aggressively deforming it to create a void, and placing the 26th circle. + The deformation helps break the initial grid symmetry. + """ + # Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # Vectorized Gaussian push to create the void. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 # Avoid division by zero for points exactly at void_center + + push_magnitudes = np.zeros(25) + # Apply push only to points not exactly at the void center + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center # The 26th circle goes into the void + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a force-directed relaxation step using vectorized calculations. + This helps quickly resolve immediate overlaps and stabilize the configuration. + """ + for _ in range(iters): + forces = np.zeros_like(self.centers) + + # Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] # (N, N, 2) + dists = np.linalg.norm(diff, axis=2) # (N, N) + + # Mask out self-interaction by setting diagonal distances to a very large value + np.fill_diagonal(dists, np.inf) + + # Repulsion mask for pairs that are close enough to interact + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + # Compute force magnitudes for interacting pairs + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + # Compute force vectors F_ij (force on i from j) + # F_ij direction is (centers[i] - centers[j]) / dists[i,j] + # Store unit vectors: normalized_diff[i,j] = (centers[i] - centers[j]) / dists[i,j] + normalized_diff = np.zeros_like(diff) + # Avoid division by zero where dists might be zero or inf (already handled diag to inf) + # The where clause ensures division only happens for valid non-zero distances. + # This covers the repulsion_mask values which are > 1e-9. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # Sum force_magnitudes[i,j] * normalized_diff[i,j] over j for each i + # This correctly sums F_ij (force exerted by j on i) for all j!=i + forces_repulsion = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + forces += forces_repulsion + + # Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + # Stagnation detection and escape parameters + stagnation_counter = 0 + stagnation_threshold = 1000 # Iterations without finding a new best to trigger a boost + perturb_boost = 1.0 + boost_factor = 3.0 # A strong, but not excessively disruptive, kick + boost_decay = 0.97 # Gradual decay of the boost + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Check for stagnation and apply a temporary perturbation boost + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + stagnation_counter = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + stagnation_counter = 0 # Reset on new best + else: + stagnation_counter += 1 # Increment on accepted but not better + else: + stagnation_counter += 1 # Increment on reject + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( + total_iterations=20000, # Increased iterations to support more thorough search with stagnation escape + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) + + # Recalculate radii after final relaxation, as SA finds centers, not perfectly relaxed radii. + final_radii = compute_max_radii(self.centers) + + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..06113b316ca79026babcf0c49ee45ffae4bea60a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": false, + "error": "'CirclePacker' object has no attribute '_select_circle_for_perturbation'" +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..ec3c31093a80dbf5e0bbc20307be8579bca24829 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_181/main.py:120: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..5642a5a829fe2c5b22e2c63486eaffe7aa021ff5 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/job_log.out @@ -0,0 +1,14 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_181/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_181/results +Evaluation error: 'CirclePacker' object has no attribute '_select_circle_for_perturbation' +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/metrics.json +Evaluation or Validation failed: 'CirclePacker' object has no attribute '_select_circle_for_perturbation' +Metrics: + combined_score: 0.0 + execution_time_mean: 0.0 + execution_time_std: 0.0 + num_successful_runs: 0 + num_valid_runs: 0 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..fec2021a6a036637c9d3049ae9778c77cef78421 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/results/metrics.json @@ -0,0 +1,9 @@ +{ + "combined_score": 0.0, + "execution_time_mean": 0.0, + "execution_time_std": 0.0, + "num_successful_runs": 0, + "num_valid_runs": 0, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b5b33c40c7b2492b521b5453d4c52af0ff3a39e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_181/search_replace.txt @@ -0,0 +1,341 @@ + +Aims to improve the Simulated Annealing phase by reintroducing multi-modal perturbation strategies (swap, clustered moves) and leveraging the full context-aware circle selection logic. It also adjusts SA parameters to be more aggressive and thorough, drawing from previous successful program configurations. This allows for better exploration and escape from local optima. + + + +<<<<<<< SEARCH + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + cluster_perturb_prob = 0.15 # Probability of performing a clustered perturbation + + # Stagnation detection and escape parameters + stagnation_counter = 0 + stagnation_threshold = 1000 # Iterations without finding a new best to trigger a boost + perturb_boost = 1.0 + boost_factor = 3.0 # A strong, but not excessively disruptive, kick + boost_decay = 0.97 # Gradual decay of the boost + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Check for stagnation and apply a temporary perturbation boost + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + stagnation_counter = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() + + # Target smaller circles for perturbation to help them grow and rearrange + # Add small constant to avoid div by zero, and ensure it's calculated from current_radii + inverse_radii = 1 / (current_radii + 1e-8) + selection_probs = inverse_radii / np.sum(inverse_radii) + + # --- Clustered or Single Circle Perturbation --- + if np.random.rand() < cluster_perturb_prob: + # Clustered perturbation: select a primary circle, then its nearest neighbors + primary_idx = np.random.choice(self.n, p=selection_probs) + + # Find the 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + # Use argsort to get indices of circles sorted by distance + # Skip the first element which is the primary_idx itself (distance 0) + neighbor_indices = np.argsort(distances_to_primary)[1:3] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate adaptive perturbation strength based on the primary circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[primary_idx] / avg_inverse_radius + # Clamp the scale factor to prevent excessively large or small perturbations. + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Generate a single displacement vector for the entire cluster + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Single circle perturbation + circle_idx = np.random.choice(self.n, p=selection_probs) + + # Apply adaptive perturbation strength based on the selected circle's inverse radius + avg_inverse_radius = np.mean(inverse_radii) + scale_factor = inverse_radii[circle_idx] / avg_inverse_radius + effective_perturb_strength = base_perturb_strength * np.clip(scale_factor, 0.7, 2.5) * perturb_boost + + # Apply a random displacement + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + stagnation_counter = 0 # Reset on new best + else: + stagnation_counter += 1 # Increment on accepted but not better + else: + stagnation_counter += 1 # Increment on reject + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( + total_iterations=20000, # Increased iterations to support more thorough search with stagnation escape + initial_temp=0.0007, # Slightly higher initial temp + final_temp=1e-9, # Slightly lower final temp + initial_perturb_strength=0.03, # Slightly larger initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) +======= + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs a simulated annealing optimization on the circle centers. + It allows for accepting 'worse' states with a decreasing probability + to escape local optima, incorporating multi-modal perturbations. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + # Perturbation strategy probabilities + swap_perturb_prob = 0.15 # Probability of performing a small-large circle swap + cluster_perturb_prob = 0.1 # Probability of performing a clustered perturbation + single_perturb_prob = 1.0 - swap_perturb_prob - cluster_perturb_prob # Remainder for single circle move + + # Stagnation detection and escape parameters (aligned with higher performing versions) + stagnation_counter = 0 + stagnation_threshold = 1200 # Iterations without finding a new best to trigger a boost + perturb_boost = 1.0 + boost_factor = 3.5 # Stronger kick + boost_decay = 0.96 # Slightly faster decay + temp_reheat_factor_on_stagnation = 0.6 # More significant reheating + + for iteration in range(total_iterations): + # Logarithmic decay for temperature and perturbation strength for finer control + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + current_temp = temp_schedule # Use the scheduled temperature by default + + # Check for stagnation and apply a temporary perturbation boost and temperature reheat + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp = temp_schedule + initial_temp * temp_reheat_factor_on_stagnation # Reheat temperature + stagnation_counter = 0 # Reset counter after triggering boost + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_perturb_prob: + # Type 1: Swap Perturbation + sorted_indices = np.argsort(current_radii) + if self.n > 1: + num_small_candidates = max(1, self.n // 4) # Consider top 25% smallest + num_large_candidates = max(1, self.n // 4) # Consider top 25% largest + + small_circles_indices = sorted_indices[:num_small_candidates] + large_circles_indices = sorted_indices[-num_large_candidates:] + + if len(small_circles_indices) > 0 and len(large_circles_indices) > 0: + idx_small = np.random.choice(small_circles_indices) + idx_large = np.random.choice(large_circles_indices) + + # Swap positions + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() + elif rand_val < swap_perturb_prob + cluster_perturb_prob: + # Type 2: Clustered Perturbation + # Select a primary circle using the full context-aware selection + primary_idx = self._select_circle_for_perturbation(current_radii, current_centers) + + # Find its 2 closest neighbors (excluding self) + distances_to_primary = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances_to_primary[primary_idx] = np.inf # Exclude self from being its own neighbor + neighbor_indices = np.argsort(distances_to_primary)[:2] # Get 2 closest neighbors + + # Collect all indices to perturb: primary + neighbors + indices_to_perturb = [primary_idx] + indices_to_perturb.extend(neighbor_indices) + + # Calculate effective perturbation for the cluster (scaled down compared to single circle) + # Use adaptive perturbation strength based on primary_idx's radius, then scale for cluster + effective_perturb_strength = self._adaptive_perturbation(base_perturb_strength, primary_idx, current_radii) * perturb_boost + cluster_move_strength = effective_perturb_strength * 0.7 # Cluster moves are generally smaller + + displacement = np.random.uniform(-cluster_move_strength, cluster_move_strength, 2) + + # Apply the displacement to all circles in the cluster + for idx in indices_to_perturb: + candidate_centers[idx] += displacement + candidate_centers[idx] = np.clip(candidate_centers[idx], 0.0, 1.0) + else: + # Type 3: Single Circle Displacement (most common perturbation) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + effective_perturb_strength = self._adaptive_perturbation(base_perturb_strength, circle_idx, current_radii) * perturb_boost + + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay the perturbation boost so its effect is temporary + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + # Evaluate the new configuration + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + # Metropolis-Hastings acceptance criterion + delta_E = candidate_sum_radii - current_sum_radii # Maximize sum of radii, so positive delta_E is better + if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): + # Accept the new state + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers + current_radii = candidate_radii + + # If this is the best state found so far, save it + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + stagnation_counter = 0 # Reset on new best + else: + stagnation_counter += 1 # Increment on accepted but not better + else: + stagnation_counter += 1 # Increment on reject + + self.centers = best_centers # Update the class's centers to the best found + return best_radii # Return best radii for convenience + + def pack(self): + """ + Orchestrates the entire packing process: + 1. Aggressive initial placement with a central void. + 2. A short, vectorized force-directed relaxation to quickly stabilize. + 3. A primary optimization phase using simulated annealing local search. + 4. A final gentle force-directed relaxation for polish. + """ + # 1. Aggressive initial placement with a *randomized* void center + # Restrict void_center to central region to allow for more diverse starting patterns. + random_void_center = np.random.uniform(0.3, 0.7, 2) + self._initial_placement_with_void_and_perturbation( + void_center=random_void_center, # Use randomized void center + amplitude=0.08, # Increased amplitude for stronger initial push to break grid + sigma=0.15 + ) + + # 2. Short, aggressive force-directed relaxation to resolve immediate chaos + self._force_directed_relaxation_vectorized( + iters=500, # More iterations for initial cleanup + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.08, + repulsion_threshold=0.19, + boundary_margin=0.04 + ) + + # 3. Simulated Annealing Local Search for global optimization + self._simulated_annealing_search( + total_iterations=35000, # Increased iterations for more thorough search + initial_temp=0.0008, # Slightly adjusted initial temp + final_temp=1e-10, # Slightly lower final temp + initial_perturb_strength=0.035, # Slightly adjusted initial perturbation + final_perturb_strength=0.0001 + ) + + # 4. After SA, apply one final gentle relaxation to ensure local stability + # and resolve any tiny remaining overlaps or improve boundary contact. + self._force_directed_relaxation_vectorized( + iters=300, + step_size=0.0001, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, + boundary_margin=0.02 + ) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..840c9f57fab44902bf04b12cd67149b73fea7396 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..b4cb714de238a23c953eb98c9a0eef0e953d54ca --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/edit.diff @@ -0,0 +1,295 @@ +--- a/original.py ++++ b/original.py +@@ -1,273 +1,288 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + + def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: Maximum iterations for convergence. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + + class CirclePacker: + """ + A class to encapsulate the logic for packing circles using a hybrid approach: + 1. Initial placement with a void to break symmetry. + 2. A force-directed relaxation phase to settle the initial state. + 3. A primary simulated annealing search with multi-modal perturbations. + 4. A final polishing phase. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void(self, void_center, amplitude, sigma): + """ + Generates an initial configuration from a 5x5 grid deformed by a Gaussian push. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a vectorized force-directed relaxation to the current centers. + """ + for _ in range(iters): + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + np.fill_diagonal(dists, np.inf) + + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _select_circle_context_aware(self, current_radii, current_centers): + """Intelligently selects a circle to perturb based on size, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(self.n) + for i in range(self.n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(self.n, p=selection_probs) + + def _adaptive_perturbation_strength(self, base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs SA with multi-modal perturbations and advanced stagnation escape. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + swap_perturb_prob = 0.15 + cluster_perturb_prob = 0.10 + + stagnation_counter = 0 + stagnation_threshold = 1200 + perturb_boost = 1.0 + boost_factor = 3.5 + boost_decay = 0.96 + temp_reheat_factor = 0.6 + + min_radii_iters, max_radii_iters = 100, 750 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) + current_temp = temp_schedule + + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp += initial_temp * temp_reheat_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_perturb_prob: + sorted_indices = np.argsort(current_radii) + if self.n > 1: + num_candidates = max(1, self.n // 4) + small_idx = np.random.choice(sorted_indices[:num_candidates]) + large_idx = np.random.choice(sorted_indices[-num_candidates:]) + if small_idx != large_idx: + candidate_centers[small_idx], candidate_centers[large_idx] = \ + candidate_centers[large_idx].copy(), candidate_centers[small_idx].copy() + + elif rand_val < swap_perturb_prob + cluster_perturb_prob: + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost * 0.7 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement + +- else: ++ else: # Single Circle Displacement, with aggressive relocation for very small circles + circle_idx = self._select_circle_context_aware(current_radii, current_centers) +- eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost +- displacement = np.random.uniform(-eff_strength, eff_strength, 2) +- candidate_centers[circle_idx] += displacement ++ ++ # Parameters for aggressive small circle relocation ++ min_relocation_radius_threshold = 0.035 # A circle is considered "very small" below this radius ++ relocation_jump_amplitude = 0.18 # Max displacement for a relocation jump (larger than standard perturbation) ++ relocation_probability_if_small = 0.25 # Probability of performing a relocation jump if the circle is very small ++ ++ if current_radii[circle_idx] < min_relocation_radius_threshold and np.random.rand() < relocation_probability_if_small: ++ # Perform an aggressive, semi-global jump for very small circles ++ # This movement is less influenced by the decaying SA perturb strength ++ displacement = np.random.uniform(-relocation_jump_amplitude, relocation_jump_amplitude, 2) ++ candidate_centers[circle_idx] += displacement ++ else: ++ # Regular adaptive perturbation for other circles or if relocation not chosen ++ eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost ++ displacement = np.random.uniform(-eff_strength, eff_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): + current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii + if current_sum_radii > best_sum_radii: + best_sum_radii, best_centers = current_sum_radii, current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + self.centers = best_centers + return compute_max_radii(best_centers) + + def pack(self): + """ + Orchestrates the entire packing process. + """ + # 1. Initial placement with a randomized void. + self._initial_placement_with_void( + void_center=np.random.uniform(0.3, 0.7, 2), + amplitude=0.08, + sigma=0.15 + ) + + # 2. Aggressive force-directed relaxation to settle. + self._force_directed_relaxation( + iters=500, step_size=0.002, repulsion_strength=0.02, + boundary_strength=0.08, repulsion_threshold=0.19, boundary_margin=0.04 + ) + + # 3. Main Simulated Annealing search for global optimization. + self._simulated_annealing_search( + total_iterations=35000, initial_temp=0.0008, final_temp=1e-10, + initial_perturb_strength=0.035, final_perturb_strength=0.0001 + ) + + # 4. Final gentle relaxation for polishing. + self._force_directed_relaxation( + iters=300, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 + ) + + final_radii = compute_max_radii(self.centers, max_iterations=1000) + return self.centers, final_radii + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the advanced CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/main.py new file mode 100644 index 0000000000000000000000000000000000000000..28bac6f804694f4944b6e94d3aa3cffb1babe896 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/main.py @@ -0,0 +1,288 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: Maximum iterations for convergence. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the logic for packing circles using a hybrid approach: + 1. Initial placement with a void to break symmetry. + 2. A force-directed relaxation phase to settle the initial state. + 3. A primary simulated annealing search with multi-modal perturbations. + 4. A final polishing phase. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void(self, void_center, amplitude, sigma): + """ + Generates an initial configuration from a 5x5 grid deformed by a Gaussian push. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a vectorized force-directed relaxation to the current centers. + """ + for _ in range(iters): + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + np.fill_diagonal(dists, np.inf) + + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _select_circle_context_aware(self, current_radii, current_centers): + """Intelligently selects a circle to perturb based on size, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(self.n) + for i in range(self.n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(self.n, p=selection_probs) + + def _adaptive_perturbation_strength(self, base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs SA with multi-modal perturbations and advanced stagnation escape. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + swap_perturb_prob = 0.15 + cluster_perturb_prob = 0.10 + + stagnation_counter = 0 + stagnation_threshold = 1200 + perturb_boost = 1.0 + boost_factor = 3.5 + boost_decay = 0.96 + temp_reheat_factor = 0.6 + + min_radii_iters, max_radii_iters = 100, 750 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) + current_temp = temp_schedule + + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp += initial_temp * temp_reheat_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_perturb_prob: + sorted_indices = np.argsort(current_radii) + if self.n > 1: + num_candidates = max(1, self.n // 4) + small_idx = np.random.choice(sorted_indices[:num_candidates]) + large_idx = np.random.choice(sorted_indices[-num_candidates:]) + if small_idx != large_idx: + candidate_centers[small_idx], candidate_centers[large_idx] = \ + candidate_centers[large_idx].copy(), candidate_centers[small_idx].copy() + + elif rand_val < swap_perturb_prob + cluster_perturb_prob: + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost * 0.7 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement + + else: # Single Circle Displacement, with aggressive relocation for very small circles + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + + # Parameters for aggressive small circle relocation + min_relocation_radius_threshold = 0.035 # A circle is considered "very small" below this radius + relocation_jump_amplitude = 0.18 # Max displacement for a relocation jump (larger than standard perturbation) + relocation_probability_if_small = 0.25 # Probability of performing a relocation jump if the circle is very small + + if current_radii[circle_idx] < min_relocation_radius_threshold and np.random.rand() < relocation_probability_if_small: + # Perform an aggressive, semi-global jump for very small circles + # This movement is less influenced by the decaying SA perturb strength + displacement = np.random.uniform(-relocation_jump_amplitude, relocation_jump_amplitude, 2) + candidate_centers[circle_idx] += displacement + else: + # Regular adaptive perturbation for other circles or if relocation not chosen + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[circle_idx] += displacement + + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): + current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii + if current_sum_radii > best_sum_radii: + best_sum_radii, best_centers = current_sum_radii, current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + self.centers = best_centers + return compute_max_radii(best_centers) + + def pack(self): + """ + Orchestrates the entire packing process. + """ + # 1. Initial placement with a randomized void. + self._initial_placement_with_void( + void_center=np.random.uniform(0.3, 0.7, 2), + amplitude=0.08, + sigma=0.15 + ) + + # 2. Aggressive force-directed relaxation to settle. + self._force_directed_relaxation( + iters=500, step_size=0.002, repulsion_strength=0.02, + boundary_strength=0.08, repulsion_threshold=0.19, boundary_margin=0.04 + ) + + # 3. Main Simulated Annealing search for global optimization. + self._simulated_annealing_search( + total_iterations=35000, initial_temp=0.0008, final_temp=1e-10, + initial_perturb_strength=0.035, final_perturb_strength=0.0001 + ) + + # 4. Final gentle relaxation for polishing. + self._force_directed_relaxation( + iters=300, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 + ) + + final_radii = compute_max_radii(self.centers, max_iterations=1000) + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the advanced CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/original.py new file mode 100644 index 0000000000000000000000000000000000000000..463ccaa138af23b302b54d7ebd83171ec33003b1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/original.py @@ -0,0 +1,273 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: Maximum iterations for convergence. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the logic for packing circles using a hybrid approach: + 1. Initial placement with a void to break symmetry. + 2. A force-directed relaxation phase to settle the initial state. + 3. A primary simulated annealing search with multi-modal perturbations. + 4. A final polishing phase. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void(self, void_center, amplitude, sigma): + """ + Generates an initial configuration from a 5x5 grid deformed by a Gaussian push. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a vectorized force-directed relaxation to the current centers. + """ + for _ in range(iters): + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + np.fill_diagonal(dists, np.inf) + + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _select_circle_context_aware(self, current_radii, current_centers): + """Intelligently selects a circle to perturb based on size, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(self.n) + for i in range(self.n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(self.n, p=selection_probs) + + def _adaptive_perturbation_strength(self, base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs SA with multi-modal perturbations and advanced stagnation escape. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + swap_perturb_prob = 0.15 + cluster_perturb_prob = 0.10 + + stagnation_counter = 0 + stagnation_threshold = 1200 + perturb_boost = 1.0 + boost_factor = 3.5 + boost_decay = 0.96 + temp_reheat_factor = 0.6 + + min_radii_iters, max_radii_iters = 100, 750 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) + current_temp = temp_schedule + + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp += initial_temp * temp_reheat_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_perturb_prob: + sorted_indices = np.argsort(current_radii) + if self.n > 1: + num_candidates = max(1, self.n // 4) + small_idx = np.random.choice(sorted_indices[:num_candidates]) + large_idx = np.random.choice(sorted_indices[-num_candidates:]) + if small_idx != large_idx: + candidate_centers[small_idx], candidate_centers[large_idx] = \ + candidate_centers[large_idx].copy(), candidate_centers[small_idx].copy() + + elif rand_val < swap_perturb_prob + cluster_perturb_prob: + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost * 0.7 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement + + else: + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[circle_idx] += displacement + + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): + current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii + if current_sum_radii > best_sum_radii: + best_sum_radii, best_centers = current_sum_radii, current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + self.centers = best_centers + return compute_max_radii(best_centers) + + def pack(self): + """ + Orchestrates the entire packing process. + """ + # 1. Initial placement with a randomized void. + self._initial_placement_with_void( + void_center=np.random.uniform(0.3, 0.7, 2), + amplitude=0.08, + sigma=0.15 + ) + + # 2. Aggressive force-directed relaxation to settle. + self._force_directed_relaxation( + iters=500, step_size=0.002, repulsion_strength=0.02, + boundary_strength=0.08, repulsion_threshold=0.19, boundary_margin=0.04 + ) + + # 3. Main Simulated Annealing search for global optimization. + self._simulated_annealing_search( + total_iterations=35000, initial_temp=0.0008, final_temp=1e-10, + initial_perturb_strength=0.035, final_perturb_strength=0.0001 + ) + + # 4. Final gentle relaxation for polishing. + self._force_directed_relaxation( + iters=300, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 + ) + + final_radii = compute_max_radii(self.centers, max_iterations=1000) + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the advanced CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..29b939feaa6a853ae0c0f2693ffe77408835d20b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_182/main.py:95: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..ccebf0f27a46ab4e2733d4f1e96cd95069e1e98a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_182/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_182/results +Run 1/1 completed in 89.07 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.364245835358002 + public: {'centers_str': ' centers[0] = (0.1000, 0.1000)\n centers[1] = (0.9018, 0.0964)\n centers[2] = (0.5083, 0.0951)\n centers[3] = (0.7040, 0.1006)\n centers[4] = (0.4419, 0.6751)\n centers[5] = (0.3067, 0.1068)\n centers[6] = (0.2797, 0.3522)\n centers[7] = (0.7711, 0.4001)\n centers[8] = (0.1373, 0.5035)\n centers[9] = (0.1018, 0.8993)\n centers[10] = (0.8969, 0.8967)\n centers[11] = (0.7297, 0.7303)\n centers[12] = (0.3705, 0.5380)\n centers[13] = (0.7060, 0.5290)\n centers[14] = (0.8955, 0.5076)\n centers[15] = (0.0988, 0.6999)\n centers[16] = (0.2983, 0.7067)\n centers[17] = (0.5425, 0.6138)\n centers[18] = (0.5241, 0.8685)\n centers[19] = (0.4398, 0.7175)\n centers[20] = (0.7245, 0.9237)\n centers[21] = (0.2988, 0.9036)\n centers[22] = (0.9207, 0.6897)\n centers[23] = (0.5459, 0.3347)\n centers[24] = (0.8965, 0.2955)\n centers[25] = (0.0966, 0.3063)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.364245835358002} + visualization_path: + execution_time_mean: 89.06539682811126 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..8e6e3a5c2e2d6de85276703a5db88b6d8b580c61 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.364245835358002, + "public": { + "centers_str": " centers[0] = (0.1000, 0.1000)\n centers[1] = (0.9018, 0.0964)\n centers[2] = (0.5083, 0.0951)\n centers[3] = (0.7040, 0.1006)\n centers[4] = (0.4419, 0.6751)\n centers[5] = (0.3067, 0.1068)\n centers[6] = (0.2797, 0.3522)\n centers[7] = (0.7711, 0.4001)\n centers[8] = (0.1373, 0.5035)\n centers[9] = (0.1018, 0.8993)\n centers[10] = (0.8969, 0.8967)\n centers[11] = (0.7297, 0.7303)\n centers[12] = (0.3705, 0.5380)\n centers[13] = (0.7060, 0.5290)\n centers[14] = (0.8955, 0.5076)\n centers[15] = (0.0988, 0.6999)\n centers[16] = (0.2983, 0.7067)\n centers[17] = (0.5425, 0.6138)\n centers[18] = (0.5241, 0.8685)\n centers[19] = (0.4398, 0.7175)\n centers[20] = (0.7245, 0.9237)\n centers[21] = (0.2988, 0.9036)\n centers[22] = (0.9207, 0.6897)\n centers[23] = (0.5459, 0.3347)\n centers[24] = (0.8965, 0.2955)\n centers[25] = (0.0966, 0.3063)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.364245835358002 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_182/results/packing_viz.png", + "execution_time_mean": 89.06539682811126, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb0e0b0d597ff847e1533b50b72d84434eb8e624 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_182/search_replace.txt @@ -0,0 +1,40 @@ + +aggressive_small_circle_relocation + + + +The visualization shows several very small circles (dark blue/purple) that appear to be 'stuck' in suboptimal positions, potentially hindering the overall packing density. While existing adaptive perturbation already gives smaller circles larger nudges, these nudges might not be enough to dislodge them from tight local minima. + +This edit introduces an "aggressive relocation" mechanism specifically for these very small circles during the single circle perturbation phase. If a selected circle's radius falls below a `min_relocation_radius_threshold`, there's a `relocation_probability_if_small` chance that it will be moved with a significantly larger, fixed-amplitude random displacement (`relocation_jump_amplitude`). This larger jump is less dependent on the decaying SA perturbation strength, allowing these potentially trapped circles to break free and explore new regions, which can open up space for larger circles or a more efficient overall arrangement. The clipping for the moved circle is now handled immediately after its displacement within this perturbation type. + + + +<<<<<<< SEARCH + else: + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[circle_idx] += displacement +======= + else: # Single Circle Displacement, with aggressive relocation for very small circles + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + + # Parameters for aggressive small circle relocation + min_relocation_radius_threshold = 0.035 # A circle is considered "very small" below this radius + relocation_jump_amplitude = 0.18 # Max displacement for a relocation jump (larger than standard perturbation) + relocation_probability_if_small = 0.25 # Probability of performing a relocation jump if the circle is very small + + if current_radii[circle_idx] < min_relocation_radius_threshold and np.random.rand() < relocation_probability_if_small: + # Perform an aggressive, semi-global jump for very small circles + # This movement is less influenced by the decaying SA perturb strength + displacement = np.random.uniform(-relocation_jump_amplitude, relocation_jump_amplitude, 2) + candidate_centers[circle_idx] += displacement + else: + # Regular adaptive perturbation for other circles or if relocation not chosen + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[circle_idx] += displacement + + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4470b3d0558acb68eb252e3fc6ec1f063a0bd5a8 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..3e209814a7bfec19a4bb2c497f64ecce0d50e999 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/edit.diff @@ -0,0 +1,521 @@ +--- a/original.py ++++ b/original.py +@@ -1,367 +1,306 @@ + # EVOLVE-BLOCK-START + import numpy as np ++import math # Needed for math.exp + + # Utility functions (kept outside classes as they are general calculations) + def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + + def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +- +-class CirclePackingProblem: +- """ +- Encapsulates the definition of the circle packing problem for n circles +- within a unit square, including initialization, evaluation, and perturbation +- strategies. ++class CirclePacker: ++ """ ++ Encapsulates the logic for constructing a high-density arrangement of circles ++ using an asymmetric grid initialization, a pre-optimization force-directed ++ relaxation, and a Simulated Annealing local search with adaptive perturbations. ++ Combines features from high-performing ancestors. + """ + def __init__(self, n): + self.n = n +- self.centers = None +- self.radii = None ++ self.centers = np.zeros((n, 2)) ++ self.radii = np.zeros(n) + self.sum_radii = 0.0 + +- def _initialize_base_centers(self): ++ def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles +- and places the 26th in an asymmetric void. ++ and places the 26th in an asymmetric void (from Program 2). + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- void_center = np.array([0.4, 0.2]) +- amplitude = 0.06 +- sigma = 0.15 ++ void_center = np.array([0.4, 0.2]) # From Program 2, a good known starting point ++ amplitude = 0.06 # From Program 2 ++ sigma = 0.15 # From Program 2 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + +- initial_centers = np.zeros((self.n, 2)) +- initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] +- initial_centers[25] = void_center +- return np.clip(initial_centers, 0.0, 1.0) +- +- def _run_force_directed_pre_optimization(self): +- """ +- Applies multiple force-directed relaxation configurations and selects +- the one yielding the highest sum of radii (Recommendation 4). +- """ +- initial_base_centers = self._initialize_base_centers() +- best_pre_opt_centers = initial_base_centers.copy() +- best_pre_opt_sum_radii = 0.0 +- +- # Define multiple parameter sets for F-D relaxation to explore different initial states +- param_sets = [ +- # Mild-aggressive +- {'iterations': 500, 'step_size': 0.001, 'repulsion_strength': 0.01, +- 'repulsion_threshold': 0.18, 'boundary_strength': 0.05, 'boundary_margin': 0.03}, +- # More aggressive (from high-performing G169) +- {'iterations': 800, 'step_size': 0.0015, 'repulsion_strength': 0.015, +- 'repulsion_threshold': 0.22, 'boundary_strength': 0.08, 'boundary_margin': 0.03}, +- # Balanced +- {'iterations': 600, 'step_size': 0.0012, 'repulsion_strength': 0.012, +- 'repulsion_threshold': 0.20, 'boundary_strength': 0.06, 'boundary_margin': 0.03}, +- # Slightly denser (reduced repulsion threshold) +- {'iterations': 700, 'step_size': 0.0013, 'repulsion_strength': 0.011, +- 'repulsion_threshold': 0.19, 'boundary_strength': 0.055, 'boundary_margin': 0.03}, +- ] +- +- for params in param_sets: +- relaxed_centers = apply_force_directed_relaxation(initial_base_centers.copy(), **params) +- radii = compute_max_radii(relaxed_centers) +- current_sum_radii = np.sum(radii) +- if current_sum_radii > best_pre_opt_sum_radii: +- best_pre_opt_sum_radii = current_sum_radii +- best_pre_opt_centers = relaxed_centers.copy() +- +- self.centers = best_pre_opt_centers ++ self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ self.centers[25] = void_center ++ self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) +- return self.centers, self.radii, self.sum_radii + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, +- and local crowding (Recommendation 2). ++ and local crowding (combining Program 1 and 2 heuristics). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) +- boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) +- +- # Local Crowding Metric ++ boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) # From Program 2 ++ ++ # Local Crowding Metric (from Program 1) - helps prioritize circles in dense regions + crowding_metric = np.zeros(self.n) +- crowding_threshold = 0.25 ++ crowding_threshold = 0.25 # Distance threshold to consider another circle 'crowding' + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + +- max_crowding = self.n - 1 ++ max_crowding = self.n - 1 # Maximum possible neighbors + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) +- crowding_influence_factor = 0.8 +- ++ crowding_influence_factor = 0.8 # How much crowding influences selection (tuneable) ++ ++ # Combine all weights: inverse radii * boundary proximity * crowding + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. +- Smaller circles receive a proportionally larger perturbation. +- """ +- max_r = np.max(current_radii) + 1e-8 ++ Smaller circles receive a proportionally larger perturbation (from Program 2). ++ """ ++ max_r = np.max(current_radii) + 1e-8 # Avoid division by zero + relative_radius = current_radii[circle_idx] / max_r +- perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 ++ perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 # More aggressive movement for smaller circles + return global_perturb_strength * perturb_factor + +- def _generate_neighbor_state(self, current_centers, current_radii, global_perturb_strength, SA_iteration, total_SA_iterations): +- """ +- Generates a new candidate state by perturbing one or more circles. +- Combines single-circle perturbation with multi-modal cluster perturbation (Recommendation 3). +- """ +- candidate_centers = current_centers.copy() ++ def pack(self): ++ """ ++ Executes the full packing process: initialization, pre-optimization, ++ and Simulated Annealing with advanced heuristics. ++ """ ++ self._initialize_centers() ++ ++ # Pre-optimization with F-D relaxation using parameters from Program 2's best config ++ self.centers = apply_force_directed_relaxation( ++ self.centers.copy(), ++ iterations=600, # From Program 2 ++ step_size=0.001, # From Program 2 ++ repulsion_strength=0.01, # From Program 2 ++ repulsion_threshold=0.20, # From Program 2 ++ boundary_strength=0.05, # From Program 2 ++ boundary_margin=0.03 # From Program 2 ++ ) ++ self.radii = compute_max_radii(self.centers) ++ self.sum_radii = np.sum(self.radii) ++ ++ # Initialize current and best states for Simulated Annealing ++ best_centers = self.centers.copy() ++ best_radii = self.radii.copy() ++ best_sum_radii = self.sum_radii ++ ++ current_centers = self.centers.copy() ++ current_radii = self.radii.copy() ++ current_sum_radii = self.sum_radii ++ ++ # SA parameters from Program 2, as they performed better ++ total_iterations = 15000 ++ initial_global_perturb_strength_base = 0.04 ++ final_global_perturb_strength = 0.0003 ++ T_initial = 0.2 ++ T_final = 1e-7 ++ ++ # Stagnation escape mechanism parameters (from Program 1's more advanced version) ++ no_improvement_count = 0 ++ max_no_improvement_steps = 500 # From Program 2's value ++ current_initial_perturb = initial_global_perturb_strength_base # This will be permanently boosted ++ stagnation_boost_active_counter = 0 ++ stagnation_boost_duration = 200 # Duration for temporary aggressive boost ++ stagnation_aggressive_perturb_multiplier = 2.0 # Multiplier for temporary boost + +- # Determine adaptive compute_max_radii iterations (Recommendation 5) +- min_radii_iter = 100 +- max_radii_iter = 750 +- current_radii_iterations = int(min_radii_iter + (max_radii_iter - min_radii_iter) * (SA_iteration / total_SA_iterations)) +- if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration +- +- # Multi-modal perturbation choice (Recommendation 3) +- # With a low probability, perturb a cluster instead of a single circle +- if np.random.rand() < 0.15: # Increased chance for cluster perturbation to 15% +- circle_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster ++ # Cluster perturbation probability (from Program 1) ++ cluster_perturb_prob = 0.15 ++ ++ for iteration in range(total_iterations): ++ # Annealing schedules ++ # Global perturbation strength decays from initial_global_perturb_strength_base (potentially boosted) to final ++ global_perturb_strength = current_initial_perturb * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + +- all_indices = np.arange(self.n) +- other_indices = np.delete(all_indices, circle_idx) +- +- if len(other_indices) > 0: +- distances = np.linalg.norm(current_centers[circle_idx] - current_centers[other_indices], axis=1) +- sorted_neighbor_indices = other_indices[np.argsort(distances)] ++ # Apply temporary aggressive perturbation if in stagnation escape ++ if stagnation_boost_active_counter > 0: ++ global_perturb_strength *= stagnation_aggressive_perturb_multiplier ++ stagnation_boost_active_counter -= 1 ++ ++ # Temperature decays exponentially ++ temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) ++ ++ candidate_centers = current_centers.copy() ++ ++ # Determine adaptive compute_max_radii iterations (from Program 1) ++ # Starts with fewer iterations, increases precision towards the end ++ min_radii_iter = 100 ++ max_radii_iter = 750 ++ current_radii_iterations = int(min_radii_iter + (max_radii_iter - min_radii_iter) * (iteration / total_iterations)) ++ if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration ++ ++ # Multi-modal perturbation choice: cluster or single circle (from Program 1) ++ if np.random.rand() < cluster_perturb_prob: ++ primary_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster + +- cluster_indices = [circle_idx] +- num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors +- for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): +- cluster_indices.append(sorted_neighbor_indices[i]) ++ # Find closest neighbors to form a cluster ++ all_indices = np.arange(self.n) ++ other_indices = np.delete(all_indices, primary_idx) + +- # Apply a coordinated, smaller displacement to the cluster +- eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) +- cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move +- +- # Generate a single random direction for the entire cluster +- angle = np.random.uniform(0, 2 * np.pi) +- direction = np.array([np.cos(angle), np.sin(angle)]) +- cluster_displacement = cluster_displacement_magnitude * direction +- +- for c_idx in cluster_indices: +- candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) +- else: # Fallback to single circle if no neighbors for cluster ++ if len(other_indices) > 0: ++ distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) ++ sorted_neighbor_indices = other_indices[np.argsort(distances)] ++ ++ cluster_indices = [primary_idx] ++ num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors ++ for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): ++ cluster_indices.append(sorted_neighbor_indices[i]) ++ ++ # Apply a coordinated, smaller displacement to the entire cluster ++ eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) ++ cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move ++ ++ # Generate a single random direction for the entire cluster ++ angle = np.random.uniform(0, 2 * np.pi) ++ direction = np.array([math.cos(angle), math.sin(angle)]) ++ cluster_displacement = cluster_displacement_magnitude * direction ++ ++ for c_idx in cluster_indices: ++ candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) ++ else: # Fallback to single circle if no neighbors for cluster (e.g., n=1) ++ circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) ++ eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) ++ displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) ++ ++ else: # Single circle perturbation (most common case, using adaptive selection and strength) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + +- else: # Single circle perturbation (most common case) +- circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) +- eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) +- displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) +- +- candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) +- candidate_sum_radii = np.sum(candidate_radii) +- +- return candidate_centers, candidate_radii, candidate_sum_radii +- +-class SimulatedAnnealingOptimizer: +- """ +- Generic Simulated Annealing optimizer. +- It takes a problem instance that defines initialization, evaluation, +- and neighbor generation. +- """ +- def __init__(self, problem, total_iterations, T_initial, T_final, +- initial_perturb_base, final_perturb, max_no_improvement_steps, +- stagnation_boost_duration, stagnation_aggressive_perturb_multiplier): +- +- self.problem = problem +- self.total_iterations = total_iterations +- self.T_initial = T_initial +- self.T_final = T_final +- self.initial_perturb_base = initial_perturb_base +- self.final_perturb = final_perturb +- self.max_no_improvement_steps = max_no_improvement_steps +- self.stagnation_boost_duration = stagnation_boost_duration +- self.stagnation_aggressive_perturb_multiplier = stagnation_aggressive_perturb_multiplier +- +- self.best_centers = None +- self.best_radii = None +- self.best_sum_radii = -np.inf +- +- def run(self): +- """ +- Executes the Simulated Annealing process. +- """ +- # Initial state from the problem's pre-optimization +- current_centers, current_radii, current_sum_radii = self.problem.centers, self.problem.radii, self.problem.sum_radii +- +- self.best_centers = current_centers.copy() +- self.best_radii = current_radii.copy() +- self.best_sum_radii = current_sum_radii +- +- no_improvement_count = 0 +- current_initial_perturb = self.initial_perturb_base +- stagnation_boost_active_counter = 0 +- +- for iteration in range(self.total_iterations): +- # Annealing schedules +- global_perturb_strength = current_initial_perturb * (1 - iteration / self.total_iterations) + self.final_perturb * (iteration / self.total_iterations) +- +- # Apply temporary aggressive perturbation if in stagnation escape (Recommendation 1) +- if stagnation_boost_active_counter > 0: +- global_perturb_strength *= self.stagnation_aggressive_perturb_multiplier +- stagnation_boost_active_counter -= 1 +- +- temperature = self.T_initial * (self.T_final / self.T_initial)**(iteration / self.total_iterations) +- +- # Generate candidate state using problem's specific method +- candidate_centers, candidate_radii, candidate_sum_radii = self.problem._generate_neighbor_state( +- current_centers, current_radii, global_perturb_strength, iteration, self.total_iterations +- ) ++ # Evaluate candidate configuration using adaptive iterations for compute_max_radii ++ candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) ++ candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + accepted = False +- if candidate_sum_radii > current_sum_radii: ++ delta = candidate_sum_radii - current_sum_radii ++ # Accept better solutions or worse solutions with probability based on temperature ++ if delta > 0 or (temperature > 1e-10 and np.random.rand() < math.exp(delta / temperature)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True +- else: +- delta = candidate_sum_radii - current_sum_radii +- acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 +- if np.random.rand() < acceptance_prob: +- current_sum_radii = candidate_sum_radii +- current_centers = candidate_centers.copy() +- current_radii = candidate_radii.copy() +- accepted = True +- +- # Update best solution and manage stagnation (Recommendation 1) +- if current_sum_radii > self.best_sum_radii: +- self.best_sum_radii = current_sum_radii +- self.best_centers = current_centers.copy() +- self.best_radii = current_radii.copy() +- no_improvement_count = 0 ++ ++ # Update best solution and manage stagnation ++ if current_sum_radii > best_sum_radii: ++ best_sum_radii = current_sum_radii ++ best_centers = current_centers.copy() ++ best_radii = current_radii.copy() ++ no_improvement_count = 0 # Reset on new best solution + elif not accepted: + no_improvement_count += 1 +- if no_improvement_count > self.max_no_improvement_steps: ++ # If stagnated for max_no_improvement_steps, activate escape mechanism ++ if no_improvement_count > max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential +- stagnation_boost_active_counter = self.stagnation_boost_duration # Activate temporary aggressive boost ++ stagnation_boost_active_counter = stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + +- return self.best_centers, self.best_radii +- ++ return best_centers, best_radii + + def construct_packing(): + """ + Main function to construct the circle packing. +- Initializes CirclePackingProblem and runs SimulatedAnnealingOptimizer. +- """ +- n_circles = 26 +- problem = CirclePackingProblem(n_circles) +- +- # Pre-optimization phase (Recommendation 4) +- # This sets problem.centers, problem.radii, problem.sum_radii +- problem._run_force_directed_pre_optimization() +- +- # Simulated Annealing parameters +- sa_params = { +- 'total_iterations': 25000, +- 'T_initial': 0.4, +- 'T_final': 1e-9, +- 'initial_perturb_base': 0.06, +- 'final_perturb': 0.0001, +- 'max_no_improvement_steps': 1000, +- 'stagnation_boost_duration': 200, +- 'stagnation_aggressive_perturb_multiplier': 2.0 +- } +- +- optimizer = SimulatedAnnealingOptimizer(problem, **sa_params) +- return optimizer.run() +- ++ Initializes CirclePacker and runs its packing method. ++ """ ++ packer = CirclePacker(n=26) ++ return packer.pack() + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/main.py new file mode 100644 index 0000000000000000000000000000000000000000..fb43d7ae0b4ea5fbed60e3d22ca28d474aaa2c99 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/main.py @@ -0,0 +1,306 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math # Needed for math.exp + +# Utility functions (kept outside classes as they are general calculations) +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + Combines features from high-performing ancestors. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void (from Program 2). + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) # From Program 2, a good known starting point + amplitude = 0.06 # From Program 2 + sigma = 0.15 # From Program 2 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding (combining Program 1 and 2 heuristics). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) # From Program 2 + + # Local Crowding Metric (from Program 1) - helps prioritize circles in dense regions + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 # Distance threshold to consider another circle 'crowding' + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 # Maximum possible neighbors + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 # How much crowding influences selection (tuneable) + + # Combine all weights: inverse radii * boundary proximity * crowding + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation (from Program 2). + """ + max_r = np.max(current_radii) + 1e-8 # Avoid division by zero + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 # More aggressive movement for smaller circles + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing with advanced heuristics. + """ + self._initialize_centers() + + # Pre-optimization with F-D relaxation using parameters from Program 2's best config + self.centers = apply_force_directed_relaxation( + self.centers.copy(), + iterations=600, # From Program 2 + step_size=0.001, # From Program 2 + repulsion_strength=0.01, # From Program 2 + repulsion_threshold=0.20, # From Program 2 + boundary_strength=0.05, # From Program 2 + boundary_margin=0.03 # From Program 2 + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + # Initialize current and best states for Simulated Annealing + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + # SA parameters from Program 2, as they performed better + total_iterations = 15000 + initial_global_perturb_strength_base = 0.04 + final_global_perturb_strength = 0.0003 + T_initial = 0.2 + T_final = 1e-7 + + # Stagnation escape mechanism parameters (from Program 1's more advanced version) + no_improvement_count = 0 + max_no_improvement_steps = 500 # From Program 2's value + current_initial_perturb = initial_global_perturb_strength_base # This will be permanently boosted + stagnation_boost_active_counter = 0 + stagnation_boost_duration = 200 # Duration for temporary aggressive boost + stagnation_aggressive_perturb_multiplier = 2.0 # Multiplier for temporary boost + + # Cluster perturbation probability (from Program 1) + cluster_perturb_prob = 0.15 + + for iteration in range(total_iterations): + # Annealing schedules + # Global perturbation strength decays from initial_global_perturb_strength_base (potentially boosted) to final + global_perturb_strength = current_initial_perturb * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape + if stagnation_boost_active_counter > 0: + global_perturb_strength *= stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + # Temperature decays exponentially + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (from Program 1) + # Starts with fewer iterations, increases precision towards the end + min_radii_iter = 100 + max_radii_iter = 750 + current_radii_iterations = int(min_radii_iter + (max_radii_iter - min_radii_iter) * (iteration / total_iterations)) + if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration + + # Multi-modal perturbation choice: cluster or single circle (from Program 1) + if np.random.rand() < cluster_perturb_prob: + primary_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster + + # Find closest neighbors to form a cluster + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [primary_idx] + num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + # Apply a coordinated, smaller displacement to the entire cluster + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move + + # Generate a single random direction for the entire cluster + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle if no neighbors for cluster (e.g., n=1) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case, using adaptive selection and strength) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluate candidate configuration using adaptive iterations for compute_max_radii + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + accepted = False + delta = candidate_sum_radii - current_sum_radii + # Accept better solutions or worse solutions with probability based on temperature + if delta > 0 or (temperature > 1e-10 and np.random.rand() < math.exp(delta / temperature)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best solution + elif not accepted: + no_improvement_count += 1 + # If stagnated for max_no_improvement_steps, activate escape mechanism + if no_improvement_count > max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential + stagnation_boost_active_counter = stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePacker and runs its packing method. + """ + packer = CirclePacker(n=26) + return packer.pack() +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/original.py new file mode 100644 index 0000000000000000000000000000000000000000..a9e00878b90e1ac9653142eaaa1af28c2bbce51a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/original.py @@ -0,0 +1,367 @@ +# EVOLVE-BLOCK-START +import numpy as np + +# Utility functions (kept outside classes as they are general calculations) +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + +class CirclePackingProblem: + """ + Encapsulates the definition of the circle packing problem for n circles + within a unit square, including initialization, evaluation, and perturbation + strategies. + """ + def __init__(self, n): + self.n = n + self.centers = None + self.radii = None + self.sum_radii = 0.0 + + def _initialize_base_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + def _run_force_directed_pre_optimization(self): + """ + Applies multiple force-directed relaxation configurations and selects + the one yielding the highest sum of radii (Recommendation 4). + """ + initial_base_centers = self._initialize_base_centers() + best_pre_opt_centers = initial_base_centers.copy() + best_pre_opt_sum_radii = 0.0 + + # Define multiple parameter sets for F-D relaxation to explore different initial states + param_sets = [ + # Mild-aggressive + {'iterations': 500, 'step_size': 0.001, 'repulsion_strength': 0.01, + 'repulsion_threshold': 0.18, 'boundary_strength': 0.05, 'boundary_margin': 0.03}, + # More aggressive (from high-performing G169) + {'iterations': 800, 'step_size': 0.0015, 'repulsion_strength': 0.015, + 'repulsion_threshold': 0.22, 'boundary_strength': 0.08, 'boundary_margin': 0.03}, + # Balanced + {'iterations': 600, 'step_size': 0.0012, 'repulsion_strength': 0.012, + 'repulsion_threshold': 0.20, 'boundary_strength': 0.06, 'boundary_margin': 0.03}, + # Slightly denser (reduced repulsion threshold) + {'iterations': 700, 'step_size': 0.0013, 'repulsion_strength': 0.011, + 'repulsion_threshold': 0.19, 'boundary_strength': 0.055, 'boundary_margin': 0.03}, + ] + + for params in param_sets: + relaxed_centers = apply_force_directed_relaxation(initial_base_centers.copy(), **params) + radii = compute_max_radii(relaxed_centers) + current_sum_radii = np.sum(radii) + if current_sum_radii > best_pre_opt_sum_radii: + best_pre_opt_sum_radii = current_sum_radii + best_pre_opt_centers = relaxed_centers.copy() + + self.centers = best_pre_opt_centers + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + return self.centers, self.radii, self.sum_radii + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding (Recommendation 2). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 + + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation. + """ + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 + return global_perturb_strength * perturb_factor + + def _generate_neighbor_state(self, current_centers, current_radii, global_perturb_strength, SA_iteration, total_SA_iterations): + """ + Generates a new candidate state by perturbing one or more circles. + Combines single-circle perturbation with multi-modal cluster perturbation (Recommendation 3). + """ + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (Recommendation 5) + min_radii_iter = 100 + max_radii_iter = 750 + current_radii_iterations = int(min_radii_iter + (max_radii_iter - min_radii_iter) * (SA_iteration / total_SA_iterations)) + if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration + + # Multi-modal perturbation choice (Recommendation 3) + # With a low probability, perturb a cluster instead of a single circle + if np.random.rand() < 0.15: # Increased chance for cluster perturbation to 15% + circle_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster + + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, circle_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[circle_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [circle_idx] + num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + # Apply a coordinated, smaller displacement to the cluster + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move + + # Generate a single random direction for the entire cluster + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([np.cos(angle), np.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle if no neighbors for cluster + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + return candidate_centers, candidate_radii, candidate_sum_radii + +class SimulatedAnnealingOptimizer: + """ + Generic Simulated Annealing optimizer. + It takes a problem instance that defines initialization, evaluation, + and neighbor generation. + """ + def __init__(self, problem, total_iterations, T_initial, T_final, + initial_perturb_base, final_perturb, max_no_improvement_steps, + stagnation_boost_duration, stagnation_aggressive_perturb_multiplier): + + self.problem = problem + self.total_iterations = total_iterations + self.T_initial = T_initial + self.T_final = T_final + self.initial_perturb_base = initial_perturb_base + self.final_perturb = final_perturb + self.max_no_improvement_steps = max_no_improvement_steps + self.stagnation_boost_duration = stagnation_boost_duration + self.stagnation_aggressive_perturb_multiplier = stagnation_aggressive_perturb_multiplier + + self.best_centers = None + self.best_radii = None + self.best_sum_radii = -np.inf + + def run(self): + """ + Executes the Simulated Annealing process. + """ + # Initial state from the problem's pre-optimization + current_centers, current_radii, current_sum_radii = self.problem.centers, self.problem.radii, self.problem.sum_radii + + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + self.best_sum_radii = current_sum_radii + + no_improvement_count = 0 + current_initial_perturb = self.initial_perturb_base + stagnation_boost_active_counter = 0 + + for iteration in range(self.total_iterations): + # Annealing schedules + global_perturb_strength = current_initial_perturb * (1 - iteration / self.total_iterations) + self.final_perturb * (iteration / self.total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape (Recommendation 1) + if stagnation_boost_active_counter > 0: + global_perturb_strength *= self.stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + temperature = self.T_initial * (self.T_final / self.T_initial)**(iteration / self.total_iterations) + + # Generate candidate state using problem's specific method + candidate_centers, candidate_radii, candidate_sum_radii = self.problem._generate_neighbor_state( + current_centers, current_radii, global_perturb_strength, iteration, self.total_iterations + ) + + # Simulated Annealing acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + delta = candidate_sum_radii - current_sum_radii + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation (Recommendation 1) + if current_sum_radii > self.best_sum_radii: + self.best_sum_radii = current_sum_radii + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + no_improvement_count = 0 + elif not accepted: + no_improvement_count += 1 + if no_improvement_count > self.max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential + stagnation_boost_active_counter = self.stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return self.best_centers, self.best_radii + + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePackingProblem and runs SimulatedAnnealingOptimizer. + """ + n_circles = 26 + problem = CirclePackingProblem(n_circles) + + # Pre-optimization phase (Recommendation 4) + # This sets problem.centers, problem.radii, problem.sum_radii + problem._run_force_directed_pre_optimization() + + # Simulated Annealing parameters + sa_params = { + 'total_iterations': 25000, + 'T_initial': 0.4, + 'T_final': 1e-9, + 'initial_perturb_base': 0.06, + 'final_perturb': 0.0001, + 'max_no_improvement_steps': 1000, + 'stagnation_boost_duration': 200, + 'stagnation_aggressive_perturb_multiplier': 2.0 + } + + optimizer = SimulatedAnnealingOptimizer(problem, **sa_params) + return optimizer.run() + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..515e8fdf2bc4351cf23913517192000d92e1a860 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_183/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_183/results +Run 1/1 completed in 38.90 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.377214535179928 + public: {'centers_str': ' centers[0] = (0.3956, 0.6443)\n centers[1] = (0.7674, 0.9088)\n centers[2] = (0.5383, 0.3113)\n centers[3] = (0.9454, 0.9455)\n centers[4] = (0.8576, 0.1389)\n centers[5] = (0.0714, 0.9245)\n centers[6] = (0.2592, 0.1026)\n centers[7] = (0.3256, 0.3375)\n centers[8] = (0.6492, 0.5554)\n centers[9] = (0.0796, 0.0802)\n centers[10] = (0.5370, 0.7747)\n centers[11] = (0.1134, 0.2718)\n centers[12] = (0.6328, 0.9486)\n centers[13] = (0.8901, 0.3856)\n centers[14] = (0.6806, 0.3159)\n centers[15] = (0.2196, 0.9232)\n centers[16] = (0.2994, 0.7314)\n centers[17] = (0.3923, 0.5392)\n centers[18] = (0.4999, 0.1418)\n centers[19] = (0.8878, 0.6097)\n centers[20] = (0.1459, 0.5253)\n centers[21] = (0.3841, 0.9119)\n centers[22] = (0.0948, 0.7596)\n centers[23] = (0.5252, 0.9434)\n centers[24] = (0.9124, 0.8075)\n centers[25] = (0.5086, 0.3958)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.377214535179928} + visualization_path: + execution_time_mean: 38.900563813280314 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..36637acf621d7738a418b1fcb122e045f41be3ac --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.377214535179928, + "public": { + "centers_str": " centers[0] = (0.3956, 0.6443)\n centers[1] = (0.7674, 0.9088)\n centers[2] = (0.5383, 0.3113)\n centers[3] = (0.9454, 0.9455)\n centers[4] = (0.8576, 0.1389)\n centers[5] = (0.0714, 0.9245)\n centers[6] = (0.2592, 0.1026)\n centers[7] = (0.3256, 0.3375)\n centers[8] = (0.6492, 0.5554)\n centers[9] = (0.0796, 0.0802)\n centers[10] = (0.5370, 0.7747)\n centers[11] = (0.1134, 0.2718)\n centers[12] = (0.6328, 0.9486)\n centers[13] = (0.8901, 0.3856)\n centers[14] = (0.6806, 0.3159)\n centers[15] = (0.2196, 0.9232)\n centers[16] = (0.2994, 0.7314)\n centers[17] = (0.3923, 0.5392)\n centers[18] = (0.4999, 0.1418)\n centers[19] = (0.8878, 0.6097)\n centers[20] = (0.1459, 0.5253)\n centers[21] = (0.3841, 0.9119)\n centers[22] = (0.0948, 0.7596)\n centers[23] = (0.5252, 0.9434)\n centers[24] = (0.9124, 0.8075)\n centers[25] = (0.5086, 0.3958)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.377214535179928 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_183/results/packing_viz.png", + "execution_time_mean": 38.900563813280314, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..78ffdc47a036caf3897d50a7507033e58b37c14a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_183/rewrite.txt @@ -0,0 +1,296 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math # Needed for math.exp + +# Utility functions (kept outside classes as they are general calculations) +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + Combines features from high-performing ancestors. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void (from Program 2). + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) # From Program 2, a good known starting point + amplitude = 0.06 # From Program 2 + sigma = 0.15 # From Program 2 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding (combining Program 1 and 2 heuristics). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) # From Program 2 + + # Local Crowding Metric (from Program 1) - helps prioritize circles in dense regions + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 # Distance threshold to consider another circle 'crowding' + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 # Maximum possible neighbors + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 # How much crowding influences selection (tuneable) + + # Combine all weights: inverse radii * boundary proximity * crowding + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation (from Program 2). + """ + max_r = np.max(current_radii) + 1e-8 # Avoid division by zero + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 # More aggressive movement for smaller circles + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing with advanced heuristics. + """ + self._initialize_centers() + + # Pre-optimization with F-D relaxation using parameters from Program 2's best config + self.centers = apply_force_directed_relaxation( + self.centers.copy(), + iterations=600, # From Program 2 + step_size=0.001, # From Program 2 + repulsion_strength=0.01, # From Program 2 + repulsion_threshold=0.20, # From Program 2 + boundary_strength=0.05, # From Program 2 + boundary_margin=0.03 # From Program 2 + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + # Initialize current and best states for Simulated Annealing + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + # SA parameters from Program 2, as they performed better + total_iterations = 15000 + initial_global_perturb_strength_base = 0.04 + final_global_perturb_strength = 0.0003 + T_initial = 0.2 + T_final = 1e-7 + + # Stagnation escape mechanism parameters (from Program 1's more advanced version) + no_improvement_count = 0 + max_no_improvement_steps = 500 # From Program 2's value + current_initial_perturb = initial_global_perturb_strength_base # This will be permanently boosted + stagnation_boost_active_counter = 0 + stagnation_boost_duration = 200 # Duration for temporary aggressive boost + stagnation_aggressive_perturb_multiplier = 2.0 # Multiplier for temporary boost + + # Cluster perturbation probability (from Program 1) + cluster_perturb_prob = 0.15 + + for iteration in range(total_iterations): + # Annealing schedules + # Global perturbation strength decays from initial_global_perturb_strength_base (potentially boosted) to final + global_perturb_strength = current_initial_perturb * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape + if stagnation_boost_active_counter > 0: + global_perturb_strength *= stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + # Temperature decays exponentially + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (from Program 1) + # Starts with fewer iterations, increases precision towards the end + min_radii_iter = 100 + max_radii_iter = 750 + current_radii_iterations = int(min_radii_iter + (max_radii_iter - min_radii_iter) * (iteration / total_iterations)) + if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration + + # Multi-modal perturbation choice: cluster or single circle (from Program 1) + if np.random.rand() < cluster_perturb_prob: + primary_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster + + # Find closest neighbors to form a cluster + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [primary_idx] + num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + # Apply a coordinated, smaller displacement to the entire cluster + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move + + # Generate a single random direction for the entire cluster + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle if no neighbors for cluster (e.g., n=1) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case, using adaptive selection and strength) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluate candidate configuration using adaptive iterations for compute_max_radii + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + accepted = False + delta = candidate_sum_radii - current_sum_radii + # Accept better solutions or worse solutions with probability based on temperature + if delta > 0 or (temperature > 1e-10 and np.random.rand() < math.exp(delta / temperature)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best solution + elif not accepted: + no_improvement_count += 1 + # If stagnated for max_no_improvement_steps, activate escape mechanism + if no_improvement_count > max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential + stagnation_boost_active_counter = stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePacker and runs its packing method. + """ + packer = CirclePacker(n=26) + return packer.pack() \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..82a5ef3e90c8225b642a3007f6e5e5ea9931370e Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..f310bc1ba6efcc5eca97d019d071096a9bec0304 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_186/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_186/results +Run 1/1 completed in 33.61 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.3010914507033626 + public: {'centers_str': ' centers[0] = (0.0805, 0.2054)\n centers[1] = (0.7204, 0.9436)\n centers[2] = (0.9197, 0.3142)\n centers[3] = (0.9430, 0.4723)\n centers[4] = (0.1918, 0.0653)\n centers[5] = (0.3145, 0.5932)\n centers[6] = (0.3067, 0.0505)\n centers[7] = (0.0631, 0.0630)\n centers[8] = (0.4278, 0.0727)\n centers[9] = (0.4578, 0.6964)\n centers[10] = (0.0978, 0.3862)\n centers[11] = (0.2867, 0.2407)\n centers[12] = (0.5977, 0.9328)\n centers[13] = (0.8824, 0.1201)\n centers[14] = (0.8893, 0.6313)\n centers[15] = (0.1034, 0.7345)\n centers[16] = (0.1822, 0.5557)\n centers[17] = (0.0712, 0.9142)\n centers[18] = (0.8793, 0.8650)\n centers[19] = (0.7477, 0.4077)\n centers[20] = (0.2422, 0.8995)\n centers[21] = (0.4427, 0.8638)\n centers[22] = (0.4551, 0.4814)\n centers[23] = (0.6505, 0.7265)\n centers[24] = (0.3081, 0.7050)\n centers[25] = (0.6278, 0.1381)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.3010914507033626} + visualization_path: + execution_time_mean: 33.61082974122837 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..caea837fbbb92ffc78016d19c1bc85b685ee75c8 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.3010914507033626, + "public": { + "centers_str": " centers[0] = (0.0805, 0.2054)\n centers[1] = (0.7204, 0.9436)\n centers[2] = (0.9197, 0.3142)\n centers[3] = (0.9430, 0.4723)\n centers[4] = (0.1918, 0.0653)\n centers[5] = (0.3145, 0.5932)\n centers[6] = (0.3067, 0.0505)\n centers[7] = (0.0631, 0.0630)\n centers[8] = (0.4278, 0.0727)\n centers[9] = (0.4578, 0.6964)\n centers[10] = (0.0978, 0.3862)\n centers[11] = (0.2867, 0.2407)\n centers[12] = (0.5977, 0.9328)\n centers[13] = (0.8824, 0.1201)\n centers[14] = (0.8893, 0.6313)\n centers[15] = (0.1034, 0.7345)\n centers[16] = (0.1822, 0.5557)\n centers[17] = (0.0712, 0.9142)\n centers[18] = (0.8793, 0.8650)\n centers[19] = (0.7477, 0.4077)\n centers[20] = (0.2422, 0.8995)\n centers[21] = (0.4427, 0.8638)\n centers[22] = (0.4551, 0.4814)\n centers[23] = (0.6505, 0.7265)\n centers[24] = (0.3081, 0.7050)\n centers[25] = (0.6278, 0.1381)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.3010914507033626 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_186/results/packing_viz.png", + "execution_time_mean": 33.61082974122837, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a0d1c6fbd5f65a9b54f06d59112985c2816f46e Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..d1b75abb492925899583a578c4f0765d012e7b75 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_188/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_188/results +Run 1/1 completed in 52.28 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.3429302226355317 + public: {'centers_str': ' centers[0] = (0.4171, 0.6441)\n centers[1] = (0.2560, 0.9055)\n centers[2] = (0.0949, 0.8973)\n centers[3] = (0.5010, 0.9373)\n centers[4] = (0.2169, 0.7390)\n centers[5] = (0.8501, 0.2474)\n centers[6] = (0.8833, 0.6050)\n centers[7] = (0.4262, 0.3036)\n centers[8] = (0.2550, 0.4511)\n centers[9] = (0.1620, 0.1790)\n centers[10] = (0.6175, 0.7351)\n centers[11] = (0.4588, 0.5242)\n centers[12] = (0.3421, 0.0558)\n centers[13] = (0.8827, 0.8408)\n centers[14] = (0.6805, 0.4058)\n centers[15] = (0.9124, 0.0929)\n centers[16] = (0.0821, 0.4102)\n centers[17] = (0.7083, 0.1179)\n centers[18] = (0.5979, 0.6106)\n centers[19] = (0.3789, 0.9397)\n centers[20] = (0.3099, 0.6174)\n centers[21] = (0.4384, 0.7689)\n centers[22] = (0.9171, 0.4128)\n centers[23] = (0.4908, 0.0986)\n centers[24] = (0.6664, 0.8957)\n centers[25] = (0.1058, 0.5961)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.3429302226355317} + visualization_path: + execution_time_mean: 52.2754149842076 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..76dc71ed376f79593f96dcbcaa7b4a076214c6d3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.3429302226355317, + "public": { + "centers_str": " centers[0] = (0.4171, 0.6441)\n centers[1] = (0.2560, 0.9055)\n centers[2] = (0.0949, 0.8973)\n centers[3] = (0.5010, 0.9373)\n centers[4] = (0.2169, 0.7390)\n centers[5] = (0.8501, 0.2474)\n centers[6] = (0.8833, 0.6050)\n centers[7] = (0.4262, 0.3036)\n centers[8] = (0.2550, 0.4511)\n centers[9] = (0.1620, 0.1790)\n centers[10] = (0.6175, 0.7351)\n centers[11] = (0.4588, 0.5242)\n centers[12] = (0.3421, 0.0558)\n centers[13] = (0.8827, 0.8408)\n centers[14] = (0.6805, 0.4058)\n centers[15] = (0.9124, 0.0929)\n centers[16] = (0.0821, 0.4102)\n centers[17] = (0.7083, 0.1179)\n centers[18] = (0.5979, 0.6106)\n centers[19] = (0.3789, 0.9397)\n centers[20] = (0.3099, 0.6174)\n centers[21] = (0.4384, 0.7689)\n centers[22] = (0.9171, 0.4128)\n centers[23] = (0.4908, 0.0986)\n centers[24] = (0.6664, 0.8957)\n centers[25] = (0.1058, 0.5961)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.3429302226355317 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_188/results/packing_viz.png", + "execution_time_mean": 52.2754149842076, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3b614f80b65a408d6fa239bfc4edff3ea75496e Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..ac31a375c06a09413429faad853bfca8b5f6e352 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/edit.diff @@ -0,0 +1,153 @@ +--- a/original.py ++++ b/original.py +@@ -1,122 +1,132 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid +- to create a larger void for the 26th circle. ++ to create a larger void for the 26th circle, with an improved initial grid setup. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + +- # 1. Start with the 25 centers of a 5x5 grid. +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) ++ # 1. Start with the 25 centers of a 5x5 grid, adjusted to better utilize boundary space. ++ # The range 0.05 to 0.95 provides more room for edge circles compared to 0.1 to 0.9, ++ # potentially leading to larger radii overall for the base 25 circles. ++ x_coords = np.linspace(0.05, 0.95, 5) # Centers at 0.05, 0.275, 0.5, 0.725, 0.95 ++ y_coords = np.linspace(0.05, 0.95, 5) # Spacing is 0.225 + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. +- # A central interstitial void at (0.4, 0.4) is a good candidate. +- void_center = np.array([0.4, 0.4]) ++ # This void center is chosen to be exactly in the middle of a 2x2 cluster of the ++ # newly defined 5x5 grid points, ensuring symmetry and efficient space usage. ++ # Midpoint between (0.275, 0.275) and (0.5, 0.5) is ((0.275+0.5)/2, (0.275+0.5)/2) = (0.3875, 0.3875). ++ void_center = np.array([0.3875, 0.3875]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. +- # This pushes nearby circles away to make more room. ++ # This pushes nearby circles away to make more room for the 26th circle. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: +- amplitude = 0.04 # The maximum distance to push a circle. ++ # Amplitude increased slightly to create a larger void, leveraging the denser base grid. ++ # Sigma (spread) kept similar to previous successful attempts. ++ amplitude = 0.05 # The maximum distance to push a circle. Adjusted from 0.04 to 0.05. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. +- if np.linalg.norm(pos_vector) > 1e-9: ++ if np.linalg.norm(pos_vector) > 1e-9: # Avoid division by zero if pos_vector is zero + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + +- # Clip centers to ensure they stay within the square, although the push is gentle. +- centers = np.clip(centers, 0.0, 1.0) ++ # 5. Clip centers to ensure they stay strictly within the unit square. ++ # Using a small buffer (0.001) prevents centers from being exactly on the boundary, ++ # which would lead to zero initial radius in compute_max_radii for that circle. ++ centers = np.clip(centers, 0.001, 0.999) + +- # 5. Compute maximum valid radii for the new configuration. ++ # 6. Compute maximum valid radii for the new configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. ++ # This provides a fair starting point for all circles, as their maximum ++ # possible radius is initially constrained by their closest boundary. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. +- # A high number of iterations ensures convergence for complex arrangements. ++ # A high number of iterations (500) ensures robust convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. ++ # This preserves the relative size of the two circles based on their current radii. + sum_r = radii[i] + radii[j] +- if sum_r > 1e-12: # Avoid division by zero ++ if sum_r > 1e-12: # Avoid division by zero for extremely small radii + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 +- radii[i] = 0 +- radii[j] = 0 ++ radii[i] = 0.0 ++ radii[j] = 0.0 + + changed_in_pass = True + +- # If a full pass resulted in no changes, the packing is stable. ++ # If a full pass resulted in no significant changes, the packing is stable. + if not changed_in_pass: + break + + return radii +- + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/main.py new file mode 100644 index 0000000000000000000000000000000000000000..9ecbeaa74114f96a03796cd5149ad6128346cf02 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/main.py @@ -0,0 +1,132 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle, with an improved initial grid setup. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid, adjusted to better utilize boundary space. + # The range 0.05 to 0.95 provides more room for edge circles compared to 0.1 to 0.9, + # potentially leading to larger radii overall for the base 25 circles. + x_coords = np.linspace(0.05, 0.95, 5) # Centers at 0.05, 0.275, 0.5, 0.725, 0.95 + y_coords = np.linspace(0.05, 0.95, 5) # Spacing is 0.225 + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # This void center is chosen to be exactly in the middle of a 2x2 cluster of the + # newly defined 5x5 grid points, ensuring symmetry and efficient space usage. + # Midpoint between (0.275, 0.275) and (0.5, 0.5) is ((0.275+0.5)/2, (0.275+0.5)/2) = (0.3875, 0.3875). + void_center = np.array([0.3875, 0.3875]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room for the 26th circle. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + # Amplitude increased slightly to create a larger void, leveraging the denser base grid. + # Sigma (spread) kept similar to previous successful attempts. + amplitude = 0.05 # The maximum distance to push a circle. Adjusted from 0.04 to 0.05. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: # Avoid division by zero if pos_vector is zero + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # 5. Clip centers to ensure they stay strictly within the unit square. + # Using a small buffer (0.001) prevents centers from being exactly on the boundary, + # which would lead to zero initial radius in compute_max_radii for that circle. + centers = np.clip(centers, 0.001, 0.999) + + # 6. Compute maximum valid radii for the new configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + # This provides a fair starting point for all circles, as their maximum + # possible radius is initially constrained by their closest boundary. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations (500) ensures robust convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + # This preserves the relative size of the two circles based on their current radii. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero for extremely small radii + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + + changed_in_pass = True + + # If a full pass resulted in no significant changes, the packing is stable. + if not changed_in_pass: + break + + return radii + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/original.py new file mode 100644 index 0000000000000000000000000000000000000000..e58791c9527c52e8afcb2cc5f4f5e25868e42d62 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/original.py @@ -0,0 +1,122 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.04 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the new configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..d5eea6aa342168bcad086f1c839be1d3d257402f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_19/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_19/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.5216501961481648 + public: {'centers_str': ' centers[0] = (0.0498, 0.0498)\n centers[1] = (0.2741, 0.0472)\n centers[2] = (0.5009, 0.0472)\n centers[3] = (0.7252, 0.0498)\n centers[4] = (0.9500, 0.0500)\n centers[5] = (0.0472, 0.2741)\n centers[6] = (0.2549, 0.2549)\n centers[7] = (0.5201, 0.2549)\n centers[8] = (0.7278, 0.2741)\n centers[9] = (0.9500, 0.2750)\n centers[10] = (0.0472, 0.5009)\n centers[11] = (0.2549, 0.5201)\n centers[12] = (0.5201, 0.5201)\n centers[13] = (0.7278, 0.5009)\n centers[14] = (0.9500, 0.5000)\n centers[15] = (0.0498, 0.7252)\n centers[16] = (0.2741, 0.7278)\n centers[17] = (0.5009, 0.7278)\n centers[18] = (0.7252, 0.7252)\n centers[19] = (0.9500, 0.7250)\n centers[20] = (0.0500, 0.9500)\n centers[21] = (0.2750, 0.9500)\n centers[22] = (0.5000, 0.9500)\n centers[23] = (0.7250, 0.9500)\n centers[24] = (0.9500, 0.9500)\n centers[25] = (0.3875, 0.3875)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.5216501961481648} + visualization_path: + execution_time_mean: 0.004721730947494507 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..a9b1df58df9e1a6461773242db83fdcca7683edb --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.5216501961481648, + "public": { + "centers_str": " centers[0] = (0.0498, 0.0498)\n centers[1] = (0.2741, 0.0472)\n centers[2] = (0.5009, 0.0472)\n centers[3] = (0.7252, 0.0498)\n centers[4] = (0.9500, 0.0500)\n centers[5] = (0.0472, 0.2741)\n centers[6] = (0.2549, 0.2549)\n centers[7] = (0.5201, 0.2549)\n centers[8] = (0.7278, 0.2741)\n centers[9] = (0.9500, 0.2750)\n centers[10] = (0.0472, 0.5009)\n centers[11] = (0.2549, 0.5201)\n centers[12] = (0.5201, 0.5201)\n centers[13] = (0.7278, 0.5009)\n centers[14] = (0.9500, 0.5000)\n centers[15] = (0.0498, 0.7252)\n centers[16] = (0.2741, 0.7278)\n centers[17] = (0.5009, 0.7278)\n centers[18] = (0.7252, 0.7252)\n centers[19] = (0.9500, 0.7250)\n centers[20] = (0.0500, 0.9500)\n centers[21] = (0.2750, 0.9500)\n centers[22] = (0.5000, 0.9500)\n centers[23] = (0.7250, 0.9500)\n centers[24] = (0.9500, 0.9500)\n centers[25] = (0.3875, 0.3875)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.5216501961481648 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_19/results/packing_viz.png", + "execution_time_mean": 0.004721730947494507, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..7af28edd01e4ce1001d3b28059d891dfcd395037 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_19/rewrite.txt @@ -0,0 +1,123 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle, with an improved initial grid setup. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid, adjusted to better utilize boundary space. + # The range 0.05 to 0.95 provides more room for edge circles compared to 0.1 to 0.9, + # potentially leading to larger radii overall for the base 25 circles. + x_coords = np.linspace(0.05, 0.95, 5) # Centers at 0.05, 0.275, 0.5, 0.725, 0.95 + y_coords = np.linspace(0.05, 0.95, 5) # Spacing is 0.225 + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # This void center is chosen to be exactly in the middle of a 2x2 cluster of the + # newly defined 5x5 grid points, ensuring symmetry and efficient space usage. + # Midpoint between (0.275, 0.275) and (0.5, 0.5) is ((0.275+0.5)/2, (0.275+0.5)/2) = (0.3875, 0.3875). + void_center = np.array([0.3875, 0.3875]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room for the 26th circle. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + # Amplitude increased slightly to create a larger void, leveraging the denser base grid. + # Sigma (spread) kept similar to previous successful attempts. + amplitude = 0.05 # The maximum distance to push a circle. Adjusted from 0.04 to 0.05. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: # Avoid division by zero if pos_vector is zero + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # 5. Clip centers to ensure they stay strictly within the unit square. + # Using a small buffer (0.001) prevents centers from being exactly on the boundary, + # which would lead to zero initial radius in compute_max_radii for that circle. + centers = np.clip(centers, 0.001, 0.999) + + # 6. Compute maximum valid radii for the new configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + # This provides a fair starting point for all circles, as their maximum + # possible radius is initially constrained by their closest boundary. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations (500) ensures robust convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + # This preserves the relative size of the two circles based on their current radii. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero for extremely small radii + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0.0 + radii[j] = 0.0 + + changed_in_pass = True + + # If a full pass resulted in no significant changes, the packing is stable. + if not changed_in_pass: + break + + return radii + +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c0b0f04159515ee765047ad82ec42bfe47b7213b Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..df46e2faa379603589bc01eef47e867337517971 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": false, + "error": "'CirclePacker' object has no attribute '_adaptive_perturb_strength'" +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..175c090e8185eb0740854c6174bae154e7e2555d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_191/main.py:118: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..8af914a0cd520443ba27e5892741a268f833aaa1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/job_log.out @@ -0,0 +1,14 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_191/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_191/results +Evaluation error: 'CirclePacker' object has no attribute '_adaptive_perturb_strength' +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/metrics.json +Evaluation or Validation failed: 'CirclePacker' object has no attribute '_adaptive_perturb_strength' +Metrics: + combined_score: 0.0 + execution_time_mean: 0.0 + execution_time_std: 0.0 + num_successful_runs: 0 + num_valid_runs: 0 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..fec2021a6a036637c9d3049ae9778c77cef78421 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_191/results/metrics.json @@ -0,0 +1,9 @@ +{ + "combined_score": 0.0, + "execution_time_mean": 0.0, + "execution_time_std": 0.0, + "num_successful_runs": 0, + "num_valid_runs": 0, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..559a0187655119ca436f76065ef75760ef997993 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..7aa27819612ee5e3a6d940ddc95bab8b81a77d7b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_192/main.py:83: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..0ef07d07b2866311877b03c43107d58676142f15 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_192/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_192/results +Run 1/1 completed in 103.79 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.3951049116262535 + public: {'centers_str': ' centers[0] = (0.0847, 0.0847)\n centers[1] = (0.6655, 0.6002)\n centers[2] = (0.5500, 0.0844)\n centers[3] = (0.3000, 0.7172)\n centers[4] = (0.9037, 0.0964)\n centers[5] = (0.0977, 0.9023)\n centers[6] = (0.0942, 0.3760)\n centers[7] = (0.5321, 0.2990)\n centers[8] = (0.7043, 0.2968)\n centers[9] = (0.9003, 0.2905)\n centers[10] = (0.4543, 0.4641)\n centers[11] = (0.4933, 0.6921)\n centers[12] = (0.7117, 0.1002)\n centers[13] = (0.6955, 0.4946)\n centers[14] = (0.8985, 0.5008)\n centers[15] = (0.1072, 0.6976)\n centers[16] = (0.7029, 0.6978)\n centers[17] = (0.7000, 0.9000)\n centers[18] = (0.2292, 0.4412)\n centers[19] = (0.9000, 0.8995)\n centers[20] = (0.0727, 0.5210)\n centers[21] = (0.2976, 0.8977)\n centers[22] = (0.5000, 0.8999)\n centers[23] = (0.0804, 0.2494)\n centers[24] = (0.9023, 0.7006)\n centers[25] = (0.3288, 0.1780)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.3951049116262535} + visualization_path: + execution_time_mean: 103.79148164903745 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..485be3644e99cd4b588c0219a86bcd88ef0f4dc0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.3951049116262535, + "public": { + "centers_str": " centers[0] = (0.0847, 0.0847)\n centers[1] = (0.6655, 0.6002)\n centers[2] = (0.5500, 0.0844)\n centers[3] = (0.3000, 0.7172)\n centers[4] = (0.9037, 0.0964)\n centers[5] = (0.0977, 0.9023)\n centers[6] = (0.0942, 0.3760)\n centers[7] = (0.5321, 0.2990)\n centers[8] = (0.7043, 0.2968)\n centers[9] = (0.9003, 0.2905)\n centers[10] = (0.4543, 0.4641)\n centers[11] = (0.4933, 0.6921)\n centers[12] = (0.7117, 0.1002)\n centers[13] = (0.6955, 0.4946)\n centers[14] = (0.8985, 0.5008)\n centers[15] = (0.1072, 0.6976)\n centers[16] = (0.7029, 0.6978)\n centers[17] = (0.7000, 0.9000)\n centers[18] = (0.2292, 0.4412)\n centers[19] = (0.9000, 0.8995)\n centers[20] = (0.0727, 0.5210)\n centers[21] = (0.2976, 0.8977)\n centers[22] = (0.5000, 0.8999)\n centers[23] = (0.0804, 0.2494)\n centers[24] = (0.9023, 0.7006)\n centers[25] = (0.3288, 0.1780)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.3951049116262535 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_192/results/packing_viz.png", + "execution_time_mean": 103.79148164903745, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ef1031f4b8cab777995ed52318fad367c2cd8be1 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..ccec447816b3a98f86b982b727d5f72b4f48ce2e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/edit.diff @@ -0,0 +1,453 @@ +--- a/original.py ++++ b/original.py +@@ -1,273 +1,318 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + +-def compute_max_radii(centers, max_iterations=500): ++def compute_max_radii(centers, max_iterations=750): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. +- +- Args: +- centers: np.array of shape (n, 2) with (x, y) coordinates +- max_iterations: Maximum iterations for convergence. +- +- Returns: +- np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) +- + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) +- + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True +- else: ++ else: # Ensure radii don't become tiny negative values, keep them at 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +-class CirclePacker: +- """ +- A class to encapsulate the logic for packing circles using a hybrid approach: +- 1. Initial placement with a void to break symmetry. +- 2. A force-directed relaxation phase to settle the initial state. +- 3. A primary simulated annealing search with multi-modal perturbations. +- 4. A final polishing phase. +- """ +- ++ ++class CirclePackingOrchestrator: ++ """ ++ Manages a multi-stage circle packing pipeline, structured for clarity and performance. ++ ++ This orchestrator class encapsulates the entire process, from finding a promising ++ initial configuration via a multi-start strategy to refining it with an advanced ++ Simulated Annealing algorithm and final polishing. This structure separates concerns, ++ making the process more modular and maintainable. ++ """ + def __init__(self, n=26): +- """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) +- +- def _initial_placement_with_void(self, void_center, amplitude, sigma): +- """ +- Generates an initial configuration from a 5x5 grid deformed by a Gaussian push. +- """ ++ self.best_centers = None ++ self.best_radii = None ++ self.best_sum_radii = -1.0 ++ ++ def _generate_void_config(self, void_center, amplitude, sigma): ++ """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center +- self.centers = np.clip(initial_centers, 0.0, 1.0) +- +- def _force_directed_relaxation(self, iters, step_size, repulsion_strength, +- boundary_strength, repulsion_threshold, boundary_margin): +- """ +- Applies a vectorized force-directed relaxation to the current centers. +- """ ++ return np.clip(initial_centers, 0.0, 1.0) ++ ++ ++ def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): ++ """Performs a vectorized force-directed relaxation phase for speed.""" + for _ in range(iters): + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + np.fill_diagonal(dists, np.inf) + + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + ++ def _initialize_and_select_best_start(self, num_starts=8): ++ """ ++ Runs a multi-start initialization. Generates several random starting ++ configurations, performs a quick relaxation on each, and selects the ++ best one to seed the main SA optimization. ++ """ ++ best_start_score = -1.0 ++ best_start_centers = None ++ ++ for _ in range(num_starts): ++ void_center = np.random.uniform(0.2, 0.8, 2) ++ amplitude = np.random.uniform(0.05, 0.1) ++ sigma = np.random.uniform(0.1, 0.2) ++ self.centers = self._generate_void_config(void_center, amplitude, sigma) ++ ++ self._force_directed_relaxation_vectorized( ++ iters=300, step_size=0.002, repulsion_strength=0.02, ++ boundary_strength=0.08, repulsion_threshold=0.2, boundary_margin=0.04 ++ ) ++ ++ radii = compute_max_radii(self.centers, max_iterations=100) ++ score = np.sum(radii) ++ ++ if score > best_start_score: ++ best_start_score = score ++ best_start_centers = self.centers.copy() ++ ++ self.centers = best_start_centers ++ self.best_centers = best_start_centers.copy() ++ self.best_radii = compute_max_radii(self.best_centers) ++ self.best_sum_radii = np.sum(self.best_radii) ++ + def _select_circle_context_aware(self, current_radii, current_centers): +- """Intelligently selects a circle to perturb based on size, boundary proximity, and crowding.""" ++ """Intelligently selects a circle to perturb.""" + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) +- +- neighbor_counts = np.zeros(self.n) +- for i in range(self.n): +- dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) +- crowd_dist = (current_radii[i] + current_radii) * 1.1 +- neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 +- +- max_neighbors = np.max(neighbor_counts) +- crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) +- +- combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) ++ combined_weights = inverse_radii * (1 + boundary_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(self.n, p=selection_probs) +- +- def _adaptive_perturbation_strength(self, base_strength, circle_idx, current_radii): +- """Calculates a larger perturbation for smaller circles.""" +- max_r = np.max(current_radii) + 1e-8 +- relative_radius = current_radii[circle_idx] / max_r +- perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 +- return base_strength * perturb_factor +- +- def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, +- initial_perturb_strength, final_perturb_strength): ++ ++ def _simulated_annealing_search(self): + """ +- Performs SA with multi-modal perturbations and advanced stagnation escape. ++ Performs the main optimization using SA with multi-modal perturbations, ++ adaptive parameters, and a refined stagnation escape mechanism. + """ +- best_centers = self.centers.copy() +- best_radii = compute_max_radii(best_centers) +- best_sum_radii = np.sum(best_radii) +- +- current_centers = best_centers.copy() +- current_radii = best_radii.copy() +- current_sum_radii = best_sum_radii +- +- swap_perturb_prob = 0.15 +- cluster_perturb_prob = 0.10 +- +- stagnation_counter = 0 +- stagnation_threshold = 1200 +- perturb_boost = 1.0 +- boost_factor = 3.5 +- boost_decay = 0.96 +- temp_reheat_factor = 0.6 +- +- min_radii_iters, max_radii_iters = 100, 750 ++ total_iterations = 45000 # Increased total iterations for deeper search ++ initial_temp, final_temp = 0.001, 1e-11 # Slightly lower final temperature ++ initial_perturb_strength, final_perturb_strength = 0.04, 0.0001 ++ ++ current_centers = self.centers.copy() ++ current_radii = self.best_radii.copy() ++ current_sum_radii = self.best_sum_radii ++ ++ # Adaptive perturbation probabilities ++ perturb_weights = {'swap': 0.15, 'cluster': 0.10, 'single': 0.75} # Initial probabilities ++ perturb_type_counts = {'swap': 0, 'cluster': 0, 'single': 0} ++ perturb_type_successes = {'swap': 0, 'cluster': 0, 'single': 0} ++ adaptive_prob_update_interval = 750 # Update probabilities every N iterations ++ learning_rate = 0.08 # How aggressively probabilities change ++ ++ stagnation_counter, stagnation_threshold = 0, 1000 # Reduced threshold to trigger escapes sooner ++ perturb_boost, boost_factor, boost_decay = 1.0, 4.5, 0.95 # More aggressive boost factor, faster decay ++ temp_reheat_factor = 0.7 # More significant reheating ++ ++ min_radii_iters, max_radii_iters = 200, 1000 # Increased range for radii iterations ++ ++ # Rattler specific parameters ++ min_relocation_radius_threshold = 0.045 # Increased threshold ++ relocation_jump_amplitude = 0.22 # Increased jump amplitude ++ relocation_probability_if_small = 0.45 # Increased probability + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) +- + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) ++ + current_temp = temp_schedule +- + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp += initial_temp * temp_reheat_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() +- rand_val = np.random.rand() +- +- if rand_val < swap_perturb_prob: +- sorted_indices = np.argsort(current_radii) ++ ++ # Select perturbation type based on current adaptive weights ++ perturb_choice = np.random.choice(list(perturb_weights.keys()), p=list(perturb_weights.values())) ++ perturb_type_counts[perturb_choice] += 1 ++ ++ if perturb_choice == 'swap': + if self.n > 1: ++ sorted_indices = np.argsort(current_radii) + num_candidates = max(1, self.n // 4) +- small_idx = np.random.choice(sorted_indices[:num_candidates]) +- large_idx = np.random.choice(sorted_indices[-num_candidates:]) +- if small_idx != large_idx: +- candidate_centers[small_idx], candidate_centers[large_idx] = \ +- candidate_centers[large_idx].copy(), candidate_centers[small_idx].copy() +- +- elif rand_val < swap_perturb_prob + cluster_perturb_prob: ++ idx_small = np.random.choice(sorted_indices[:num_candidates]) ++ idx_large = np.random.choice(sorted_indices[-num_candidates:]) ++ if idx_small != idx_large: ++ candidate_centers[idx_small], candidate_centers[idx_large] = \ ++ candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() ++ ++ elif perturb_choice == 'cluster': + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + +- eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost * 0.7 ++ max_r = np.max(current_radii) + 1e-8 ++ relative_radius = current_radii[primary_idx] / max_r ++ perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 ++ # Increased cluster move strength factor ++ eff_strength = base_perturb_strength * perturb_factor * perturb_boost * 0.8 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement +- +- else: ++ ++ else: # 'single' perturbation + circle_idx = self._select_circle_context_aware(current_radii, current_centers) +- eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost +- displacement = np.random.uniform(-eff_strength, eff_strength, 2) +- candidate_centers[circle_idx] += displacement ++ ++ if current_radii[circle_idx] < min_relocation_radius_threshold and np.random.rand() < relocation_probability_if_small: ++ # Aggressive relocation for rattlers to a random spot ++ candidate_centers[circle_idx] = np.random.uniform(0.05, 0.95, 2) ++ else: ++ max_r = np.max(current_radii) + 1e-8 ++ relative_radius = current_radii[circle_idx] / max_r ++ perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 ++ eff_strength = base_perturb_strength * perturb_factor * perturb_boost ++ displacement = np.random.uniform(-eff_strength, eff_strength, 2) ++ candidate_centers[circle_idx] += displacement + + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) +- + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii +- if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): ++ if delta_E > 0 or (current_temp > 1e-12 and np.random.rand() < math.exp(delta_E / current_temp)): + current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii +- if current_sum_radii > best_sum_radii: +- best_sum_radii, best_centers = current_sum_radii, current_centers.copy() ++ perturb_type_successes[perturb_choice] += 1 # Mark success for the chosen perturbation type ++ ++ if current_sum_radii > self.best_sum_radii: ++ self.best_sum_radii = current_sum_radii ++ self.best_centers = current_centers.copy() ++ self.best_radii = current_radii.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 +- +- self.centers = best_centers +- return compute_max_radii(best_centers) ++ ++ # Adapt perturbation probabilities ++ if (iteration + 1) % adaptive_prob_update_interval == 0: ++ total_counts = sum(perturb_type_counts.values()) ++ if total_counts > 0: ++ for p_type in perturb_weights.keys(): ++ count = perturb_type_counts[p_type] ++ success = perturb_type_successes[p_type] ++ ++ # Avoid division by zero if a type was never chosen or always failed ++ success_rate = success / count if count > 0 else 0.5 # Default to neutral if no data ++ ++ # Adjust weight based on success rate relative to a baseline (e.g., 50%) ++ # Using an exponential adjustment for stronger impact ++ adjustment_factor = math.exp(learning_rate * (success_rate - 0.5)) ++ perturb_weights[p_type] *= adjustment_factor ++ ++ # Normalize weights ++ sum_weights = sum(perturb_weights.values()) ++ if sum_weights > 0: ++ for p_type in perturb_weights.keys(): ++ perturb_weights[p_type] /= sum_weights ++ ++ # Reset counters ++ perturb_type_counts = {k: 0 for k in perturb_type_counts} ++ perturb_type_successes = {k: 0 for k in perturb_type_successes} ++ ++ ++ self.centers = self.best_centers.copy() ++ + + def pack(self): +- """ +- Orchestrates the entire packing process. +- """ +- # 1. Initial placement with a randomized void. +- self._initial_placement_with_void( +- void_center=np.random.uniform(0.3, 0.7, 2), +- amplitude=0.08, +- sigma=0.15 ++ """Executes the full, orchestrated packing pipeline.""" ++ self._initialize_and_select_best_start(num_starts=8) ++ ++ self._simulated_annealing_search() ++ ++ self.centers = self.best_centers.copy() ++ # Final gentle relaxation might be more effective with slightly higher repulsion ++ self._force_directed_relaxation_vectorized( ++ iters=500, step_size=0.0001, repulsion_strength=0.002, # Increased repulsion strength ++ boundary_strength=0.01, repulsion_threshold=0.18, boundary_margin=0.02 + ) + +- # 2. Aggressive force-directed relaxation to settle. +- self._force_directed_relaxation( +- iters=500, step_size=0.002, repulsion_strength=0.02, +- boundary_strength=0.08, repulsion_threshold=0.19, boundary_margin=0.04 +- ) +- +- # 3. Main Simulated Annealing search for global optimization. +- self._simulated_annealing_search( +- total_iterations=35000, initial_temp=0.0008, final_temp=1e-10, +- initial_perturb_strength=0.035, final_perturb_strength=0.0001 +- ) +- +- # 4. Final gentle relaxation for polishing. +- self._force_directed_relaxation( +- iters=300, step_size=0.0001, repulsion_strength=0.001, +- boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 +- ) +- + final_radii = compute_max_radii(self.centers, max_iterations=1000) +- return self.centers, final_radii ++ final_sum_radii = np.sum(final_radii) ++ ++ if final_sum_radii > self.best_sum_radii: ++ self.best_radii = final_radii ++ self.best_centers = self.centers ++ ++ return self.best_centers, self.best_radii + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and +- running the advanced CirclePacker class. +- """ +- packer = CirclePacker(n=26) +- centers, radii = packer.pack() ++ running the CirclePackingOrchestrator. ++ """ ++ orchestrator = CirclePackingOrchestrator(n=26) ++ centers, radii = orchestrator.pack() + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/main.py new file mode 100644 index 0000000000000000000000000000000000000000..d60a6b9ca959ff6f659227d11514d3c7c7648ed5 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/main.py @@ -0,0 +1,318 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers, max_iterations=750): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # Ensure radii don't become tiny negative values, keep them at 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + + +class CirclePackingOrchestrator: + """ + Manages a multi-stage circle packing pipeline, structured for clarity and performance. + + This orchestrator class encapsulates the entire process, from finding a promising + initial configuration via a multi-start strategy to refining it with an advanced + Simulated Annealing algorithm and final polishing. This structure separates concerns, + making the process more modular and maintainable. + """ + def __init__(self, n=26): + self.n = n + self.centers = np.zeros((n, 2)) + self.best_centers = None + self.best_radii = None + self.best_sum_radii = -1.0 + + def _generate_void_config(self, void_center, amplitude, sigma): + """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation phase for speed.""" + for _ in range(iters): + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + np.fill_diagonal(dists, np.inf) + + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _initialize_and_select_best_start(self, num_starts=8): + """ + Runs a multi-start initialization. Generates several random starting + configurations, performs a quick relaxation on each, and selects the + best one to seed the main SA optimization. + """ + best_start_score = -1.0 + best_start_centers = None + + for _ in range(num_starts): + void_center = np.random.uniform(0.2, 0.8, 2) + amplitude = np.random.uniform(0.05, 0.1) + sigma = np.random.uniform(0.1, 0.2) + self.centers = self._generate_void_config(void_center, amplitude, sigma) + + self._force_directed_relaxation_vectorized( + iters=300, step_size=0.002, repulsion_strength=0.02, + boundary_strength=0.08, repulsion_threshold=0.2, boundary_margin=0.04 + ) + + radii = compute_max_radii(self.centers, max_iterations=100) + score = np.sum(radii) + + if score > best_start_score: + best_start_score = score + best_start_centers = self.centers.copy() + + self.centers = best_start_centers + self.best_centers = best_start_centers.copy() + self.best_radii = compute_max_radii(self.best_centers) + self.best_sum_radii = np.sum(self.best_radii) + + def _select_circle_context_aware(self, current_radii, current_centers): + """Intelligently selects a circle to perturb.""" + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + combined_weights = inverse_radii * (1 + boundary_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(self.n, p=selection_probs) + + def _simulated_annealing_search(self): + """ + Performs the main optimization using SA with multi-modal perturbations, + adaptive parameters, and a refined stagnation escape mechanism. + """ + total_iterations = 45000 # Increased total iterations for deeper search + initial_temp, final_temp = 0.001, 1e-11 # Slightly lower final temperature + initial_perturb_strength, final_perturb_strength = 0.04, 0.0001 + + current_centers = self.centers.copy() + current_radii = self.best_radii.copy() + current_sum_radii = self.best_sum_radii + + # Adaptive perturbation probabilities + perturb_weights = {'swap': 0.15, 'cluster': 0.10, 'single': 0.75} # Initial probabilities + perturb_type_counts = {'swap': 0, 'cluster': 0, 'single': 0} + perturb_type_successes = {'swap': 0, 'cluster': 0, 'single': 0} + adaptive_prob_update_interval = 750 # Update probabilities every N iterations + learning_rate = 0.08 # How aggressively probabilities change + + stagnation_counter, stagnation_threshold = 0, 1000 # Reduced threshold to trigger escapes sooner + perturb_boost, boost_factor, boost_decay = 1.0, 4.5, 0.95 # More aggressive boost factor, faster decay + temp_reheat_factor = 0.7 # More significant reheating + + min_radii_iters, max_radii_iters = 200, 1000 # Increased range for radii iterations + + # Rattler specific parameters + min_relocation_radius_threshold = 0.045 # Increased threshold + relocation_jump_amplitude = 0.22 # Increased jump amplitude + relocation_probability_if_small = 0.45 # Increased probability + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) + + current_temp = temp_schedule + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp += initial_temp * temp_reheat_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + + # Select perturbation type based on current adaptive weights + perturb_choice = np.random.choice(list(perturb_weights.keys()), p=list(perturb_weights.values())) + perturb_type_counts[perturb_choice] += 1 + + if perturb_choice == 'swap': + if self.n > 1: + sorted_indices = np.argsort(current_radii) + num_candidates = max(1, self.n // 4) + idx_small = np.random.choice(sorted_indices[:num_candidates]) + idx_large = np.random.choice(sorted_indices[-num_candidates:]) + if idx_small != idx_large: + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() + + elif perturb_choice == 'cluster': + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[primary_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + # Increased cluster move strength factor + eff_strength = base_perturb_strength * perturb_factor * perturb_boost * 0.8 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement + + else: # 'single' perturbation + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + + if current_radii[circle_idx] < min_relocation_radius_threshold and np.random.rand() < relocation_probability_if_small: + # Aggressive relocation for rattlers to a random spot + candidate_centers[circle_idx] = np.random.uniform(0.05, 0.95, 2) + else: + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + eff_strength = base_perturb_strength * perturb_factor * perturb_boost + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[circle_idx] += displacement + + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (current_temp > 1e-12 and np.random.rand() < math.exp(delta_E / current_temp)): + current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii + perturb_type_successes[perturb_choice] += 1 # Mark success for the chosen perturbation type + + if current_sum_radii > self.best_sum_radii: + self.best_sum_radii = current_sum_radii + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + # Adapt perturbation probabilities + if (iteration + 1) % adaptive_prob_update_interval == 0: + total_counts = sum(perturb_type_counts.values()) + if total_counts > 0: + for p_type in perturb_weights.keys(): + count = perturb_type_counts[p_type] + success = perturb_type_successes[p_type] + + # Avoid division by zero if a type was never chosen or always failed + success_rate = success / count if count > 0 else 0.5 # Default to neutral if no data + + # Adjust weight based on success rate relative to a baseline (e.g., 50%) + # Using an exponential adjustment for stronger impact + adjustment_factor = math.exp(learning_rate * (success_rate - 0.5)) + perturb_weights[p_type] *= adjustment_factor + + # Normalize weights + sum_weights = sum(perturb_weights.values()) + if sum_weights > 0: + for p_type in perturb_weights.keys(): + perturb_weights[p_type] /= sum_weights + + # Reset counters + perturb_type_counts = {k: 0 for k in perturb_type_counts} + perturb_type_successes = {k: 0 for k in perturb_type_successes} + + + self.centers = self.best_centers.copy() + + + def pack(self): + """Executes the full, orchestrated packing pipeline.""" + self._initialize_and_select_best_start(num_starts=8) + + self._simulated_annealing_search() + + self.centers = self.best_centers.copy() + # Final gentle relaxation might be more effective with slightly higher repulsion + self._force_directed_relaxation_vectorized( + iters=500, step_size=0.0001, repulsion_strength=0.002, # Increased repulsion strength + boundary_strength=0.01, repulsion_threshold=0.18, boundary_margin=0.02 + ) + + final_radii = compute_max_radii(self.centers, max_iterations=1000) + final_sum_radii = np.sum(final_radii) + + if final_sum_radii > self.best_sum_radii: + self.best_radii = final_radii + self.best_centers = self.centers + + return self.best_centers, self.best_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the CirclePackingOrchestrator. + """ + orchestrator = CirclePackingOrchestrator(n=26) + centers, radii = orchestrator.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/original.py new file mode 100644 index 0000000000000000000000000000000000000000..f86115db3989e8fef06e14163e4b0612c39c4b05 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/original.py @@ -0,0 +1,273 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: Maximum iterations for convergence. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + +class CirclePacker: + """ + A class to encapsulate the logic for packing circles using a hybrid approach: + 1. Initial placement with a void to break symmetry. + 2. A force-directed relaxation phase to settle the initial state. + 3. A primary simulated annealing search with multi-modal perturbations. + 4. A final polishing phase. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initial_placement_with_void(self, void_center, amplitude, sigma): + """ + Generates an initial configuration from a 5x5 grid deformed by a Gaussian push. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + self.centers = np.clip(initial_centers, 0.0, 1.0) + + def _force_directed_relaxation(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Applies a vectorized force-directed relaxation to the current centers. + """ + for _ in range(iters): + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + np.fill_diagonal(dists, np.inf) + + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _select_circle_context_aware(self, current_radii, current_centers): + """Intelligently selects a circle to perturb based on size, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(self.n) + for i in range(self.n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(self.n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(self.n, p=selection_probs) + + def _adaptive_perturbation_strength(self, base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + + def _simulated_annealing_search(self, total_iterations, initial_temp, final_temp, + initial_perturb_strength, final_perturb_strength): + """ + Performs SA with multi-modal perturbations and advanced stagnation escape. + """ + best_centers = self.centers.copy() + best_radii = compute_max_radii(best_centers) + best_sum_radii = np.sum(best_radii) + + current_centers = best_centers.copy() + current_radii = best_radii.copy() + current_sum_radii = best_sum_radii + + swap_perturb_prob = 0.15 + cluster_perturb_prob = 0.10 + + stagnation_counter = 0 + stagnation_threshold = 1200 + perturb_boost = 1.0 + boost_factor = 3.5 + boost_decay = 0.96 + temp_reheat_factor = 0.6 + + min_radii_iters, max_radii_iters = 100, 750 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) + current_temp = temp_schedule + + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp += initial_temp * temp_reheat_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_perturb_prob: + sorted_indices = np.argsort(current_radii) + if self.n > 1: + num_candidates = max(1, self.n // 4) + small_idx = np.random.choice(sorted_indices[:num_candidates]) + large_idx = np.random.choice(sorted_indices[-num_candidates:]) + if small_idx != large_idx: + candidate_centers[small_idx], candidate_centers[large_idx] = \ + candidate_centers[large_idx].copy(), candidate_centers[small_idx].copy() + + elif rand_val < swap_perturb_prob + cluster_perturb_prob: + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost * 0.7 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement + + else: + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + eff_strength = self._adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[circle_idx] += displacement + + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (current_temp > 1e-10 and np.random.rand() < math.exp(delta_E / current_temp)): + current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii + if current_sum_radii > best_sum_radii: + best_sum_radii, best_centers = current_sum_radii, current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + self.centers = best_centers + return compute_max_radii(best_centers) + + def pack(self): + """ + Orchestrates the entire packing process. + """ + # 1. Initial placement with a randomized void. + self._initial_placement_with_void( + void_center=np.random.uniform(0.3, 0.7, 2), + amplitude=0.08, + sigma=0.15 + ) + + # 2. Aggressive force-directed relaxation to settle. + self._force_directed_relaxation( + iters=500, step_size=0.002, repulsion_strength=0.02, + boundary_strength=0.08, repulsion_threshold=0.19, boundary_margin=0.04 + ) + + # 3. Main Simulated Annealing search for global optimization. + self._simulated_annealing_search( + total_iterations=35000, initial_temp=0.0008, final_temp=1e-10, + initial_perturb_strength=0.035, final_perturb_strength=0.0001 + ) + + # 4. Final gentle relaxation for polishing. + self._force_directed_relaxation( + iters=300, step_size=0.0001, repulsion_strength=0.001, + boundary_strength=0.005, repulsion_threshold=0.18, boundary_margin=0.02 + ) + + final_radii = compute_max_radii(self.centers, max_iterations=1000) + return self.centers, final_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the advanced CirclePacker class. + """ + packer = CirclePacker(n=26) + centers, radii = packer.pack() + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..c02db5bd0b16bbe8b060878187f0ae8038312c8f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_193/main.py:85: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..c31adf4bebee444a559bb1c8bc878a6487073b71 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_193/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_193/results +Run 1/1 completed in 103.07 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.3421821445812743 + public: {'centers_str': ' centers[0] = (0.0696, 0.0696)\n centers[1] = (0.2132, 0.0741)\n centers[2] = (0.5863, 0.1843)\n centers[3] = (0.7431, 0.7063)\n centers[4] = (0.8632, 0.1040)\n centers[5] = (0.3432, 0.7687)\n centers[6] = (0.2867, 0.3501)\n centers[7] = (0.4893, 0.3600)\n centers[8] = (0.6815, 0.2927)\n centers[9] = (0.8998, 0.3049)\n centers[10] = (0.1041, 0.4952)\n centers[11] = (0.2975, 0.5045)\n centers[12] = (0.1005, 0.8995)\n centers[13] = (0.6940, 0.5242)\n centers[14] = (0.9030, 0.5022)\n centers[15] = (0.0998, 0.6991)\n centers[16] = (0.2796, 0.6748)\n centers[17] = (0.4789, 0.7206)\n centers[18] = (0.6479, 0.0886)\n centers[19] = (0.8996, 0.6997)\n centers[20] = (0.4846, 0.4993)\n centers[21] = (0.3093, 0.8915)\n centers[22] = (0.1319, 0.2608)\n centers[23] = (0.6756, 0.8741)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4084, 0.1618)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.3421821445812743} + visualization_path: + execution_time_mean: 103.07158300932497 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..87036c71520ce7ed17a3fd8036ec02b1d2c44ce1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.3421821445812743, + "public": { + "centers_str": " centers[0] = (0.0696, 0.0696)\n centers[1] = (0.2132, 0.0741)\n centers[2] = (0.5863, 0.1843)\n centers[3] = (0.7431, 0.7063)\n centers[4] = (0.8632, 0.1040)\n centers[5] = (0.3432, 0.7687)\n centers[6] = (0.2867, 0.3501)\n centers[7] = (0.4893, 0.3600)\n centers[8] = (0.6815, 0.2927)\n centers[9] = (0.8998, 0.3049)\n centers[10] = (0.1041, 0.4952)\n centers[11] = (0.2975, 0.5045)\n centers[12] = (0.1005, 0.8995)\n centers[13] = (0.6940, 0.5242)\n centers[14] = (0.9030, 0.5022)\n centers[15] = (0.0998, 0.6991)\n centers[16] = (0.2796, 0.6748)\n centers[17] = (0.4789, 0.7206)\n centers[18] = (0.6479, 0.0886)\n centers[19] = (0.8996, 0.6997)\n centers[20] = (0.4846, 0.4993)\n centers[21] = (0.3093, 0.8915)\n centers[22] = (0.1319, 0.2608)\n centers[23] = (0.6756, 0.8741)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4084, 0.1618)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.3421821445812743 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_193/results/packing_viz.png", + "execution_time_mean": 103.07158300932497, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..18119736f5e448e6d770b745719e1724f5d7371c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_193/rewrite.txt @@ -0,0 +1,309 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers, max_iterations=750): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + else: # Ensure radii don't become tiny negative values, keep them at 0 + radii[i] = 0.0 + radii[j] = 0.0 + changes_made = True + if not changes_made: + break + return radii + + +class CirclePackingOrchestrator: + """ + Manages a multi-stage circle packing pipeline, structured for clarity and performance. + + This orchestrator class encapsulates the entire process, from finding a promising + initial configuration via a multi-start strategy to refining it with an advanced + Simulated Annealing algorithm and final polishing. This structure separates concerns, + making the process more modular and maintainable. + """ + def __init__(self, n=26): + self.n = n + self.centers = np.zeros((n, 2)) + self.best_centers = None + self.best_radii = None + self.best_sum_radii = -1.0 + + def _generate_void_config(self, void_center, amplitude, sigma): + """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + + def _force_directed_relaxation_vectorized(self, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation phase for speed.""" + for _ in range(iters): + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + np.fill_diagonal(dists, np.inf) + + repulsion_mask = (dists < repulsion_threshold) & (dists > 1e-9) + + force_magnitudes = np.zeros_like(dists) + force_magnitudes[repulsion_mask] = repulsion_strength * (repulsion_threshold - dists[repulsion_mask]) / dists[repulsion_mask] + + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_magnitudes[:, :, np.newaxis] * normalized_diff, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _initialize_and_select_best_start(self, num_starts=8): + """ + Runs a multi-start initialization. Generates several random starting + configurations, performs a quick relaxation on each, and selects the + best one to seed the main SA optimization. + """ + best_start_score = -1.0 + best_start_centers = None + + for _ in range(num_starts): + void_center = np.random.uniform(0.2, 0.8, 2) + amplitude = np.random.uniform(0.05, 0.1) + sigma = np.random.uniform(0.1, 0.2) + self.centers = self._generate_void_config(void_center, amplitude, sigma) + + self._force_directed_relaxation_vectorized( + iters=300, step_size=0.002, repulsion_strength=0.02, + boundary_strength=0.08, repulsion_threshold=0.2, boundary_margin=0.04 + ) + + radii = compute_max_radii(self.centers, max_iterations=100) + score = np.sum(radii) + + if score > best_start_score: + best_start_score = score + best_start_centers = self.centers.copy() + + self.centers = best_start_centers + self.best_centers = best_start_centers.copy() + self.best_radii = compute_max_radii(self.best_centers) + self.best_sum_radii = np.sum(self.best_radii) + + def _select_circle_context_aware(self, current_radii, current_centers): + """Intelligently selects a circle to perturb.""" + inverse_radii = 1 / (current_radii + 1e-8) + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + combined_weights = inverse_radii * (1 + boundary_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(self.n, p=selection_probs) + + def _simulated_annealing_search(self): + """ + Performs the main optimization using SA with multi-modal perturbations, + adaptive parameters, and a refined stagnation escape mechanism. + """ + total_iterations = 45000 # Increased total iterations for deeper search + initial_temp, final_temp = 0.001, 1e-11 # Slightly lower final temperature + initial_perturb_strength, final_perturb_strength = 0.04, 0.0001 + + current_centers = self.centers.copy() + current_radii = self.best_radii.copy() + current_sum_radii = self.best_sum_radii + + # Adaptive perturbation probabilities + perturb_weights = {'swap': 0.15, 'cluster': 0.10, 'single': 0.75} # Initial probabilities + perturb_type_counts = {'swap': 0, 'cluster': 0, 'single': 0} + perturb_type_successes = {'swap': 0, 'cluster': 0, 'single': 0} + adaptive_prob_update_interval = 750 # Update probabilities every N iterations + learning_rate = 0.08 # How aggressively probabilities change + + stagnation_counter, stagnation_threshold = 0, 1000 # Reduced threshold to trigger escapes sooner + perturb_boost, boost_factor, boost_decay = 1.0, 4.5, 0.95 # More aggressive boost factor, faster decay + temp_reheat_factor = 0.7 # More significant reheating + + min_radii_iters, max_radii_iters = 200, 1000 # Increased range for radii iterations + + # Rattler specific parameters + min_relocation_radius_threshold = 0.045 # Increased threshold + relocation_jump_amplitude = 0.22 # Increased jump amplitude + relocation_probability_if_small = 0.45 # Increased probability + + for iteration in range(total_iterations): + progress = iteration / total_iterations + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + radii_iter_limit = int(min_radii_iters + (max_radii_iters - min_radii_iters) * progress) + + current_temp = temp_schedule + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + current_temp += initial_temp * temp_reheat_factor + stagnation_counter = 0 + + candidate_centers = current_centers.copy() + + # Select perturbation type based on current adaptive weights + perturb_choice = np.random.choice(list(perturb_weights.keys()), p=list(perturb_weights.values())) + perturb_type_counts[perturb_choice] += 1 + + if perturb_choice == 'swap': + if self.n > 1: + sorted_indices = np.argsort(current_radii) + num_candidates = max(1, self.n // 4) + idx_small = np.random.choice(sorted_indices[:num_candidates]) + idx_large = np.random.choice(sorted_indices[-num_candidates:]) + if idx_small != idx_large: + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() + + elif perturb_choice == 'cluster': + primary_idx = self._select_circle_context_aware(current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[primary_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + # Increased cluster move strength factor + eff_strength = base_perturb_strength * perturb_factor * perturb_boost * 0.8 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement + + else: # 'single' perturbation + circle_idx = self._select_circle_context_aware(current_radii, current_centers) + + if current_radii[circle_idx] < min_relocation_radius_threshold and np.random.rand() < relocation_probability_if_small: + # Aggressive relocation for rattlers to a random spot + candidate_centers[circle_idx] = np.random.uniform(0.05, 0.95, 2) + else: + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + eff_strength = base_perturb_strength * perturb_factor * perturb_boost + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[circle_idx] += displacement + + candidate_centers = np.clip(candidate_centers, 0.0, 1.0) + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers, max_iterations=radii_iter_limit) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (current_temp > 1e-12 and np.random.rand() < math.exp(delta_E / current_temp)): + current_sum_radii, current_centers, current_radii = candidate_sum_radii, candidate_centers, candidate_radii + perturb_type_successes[perturb_choice] += 1 # Mark success for the chosen perturbation type + + if current_sum_radii > self.best_sum_radii: + self.best_sum_radii = current_sum_radii + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + # Adapt perturbation probabilities + if (iteration + 1) % adaptive_prob_update_interval == 0: + total_counts = sum(perturb_type_counts.values()) + if total_counts > 0: + for p_type in perturb_weights.keys(): + count = perturb_type_counts[p_type] + success = perturb_type_successes[p_type] + + # Avoid division by zero if a type was never chosen or always failed + success_rate = success / count if count > 0 else 0.5 # Default to neutral if no data + + # Adjust weight based on success rate relative to a baseline (e.g., 50%) + # Using an exponential adjustment for stronger impact + adjustment_factor = math.exp(learning_rate * (success_rate - 0.5)) + perturb_weights[p_type] *= adjustment_factor + + # Normalize weights + sum_weights = sum(perturb_weights.values()) + if sum_weights > 0: + for p_type in perturb_weights.keys(): + perturb_weights[p_type] /= sum_weights + + # Reset counters + perturb_type_counts = {k: 0 for k in perturb_type_counts} + perturb_type_successes = {k: 0 for k in perturb_type_successes} + + + self.centers = self.best_centers.copy() + + + def pack(self): + """Executes the full, orchestrated packing pipeline.""" + self._initialize_and_select_best_start(num_starts=8) + + self._simulated_annealing_search() + + self.centers = self.best_centers.copy() + # Final gentle relaxation might be more effective with slightly higher repulsion + self._force_directed_relaxation_vectorized( + iters=500, step_size=0.0001, repulsion_strength=0.002, # Increased repulsion strength + boundary_strength=0.01, repulsion_threshold=0.18, boundary_margin=0.02 + ) + + final_radii = compute_max_radii(self.centers, max_iterations=1000) + final_sum_radii = np.sum(final_radii) + + if final_sum_radii > self.best_sum_radii: + self.best_radii = final_radii + self.best_centers = self.centers + + return self.best_centers, self.best_radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by instantiating and + running the CirclePackingOrchestrator. + """ + orchestrator = CirclePackingOrchestrator(n=26) + centers, radii = orchestrator.pack() + return centers, radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7258a5159e5b3f6eae3457cae6df884db805208a Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..d67c513d4659f108b42380e69b102aaf16a919c7 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/edit.diff @@ -0,0 +1,445 @@ +--- a/original.py ++++ b/original.py +@@ -1,367 +1,398 @@ + # EVOLVE-BLOCK-START + import numpy as np ++import math # Needed for math.exp + + # Utility functions (kept outside classes as they are general calculations) + def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + + def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + + class CirclePackingProblem: + """ + Encapsulates the definition of the circle packing problem for n circles + within a unit square, including initialization, evaluation, and perturbation + strategies. + """ + def __init__(self, n): + self.n = n + self.centers = None + self.radii = None + self.sum_radii = 0.0 + + def _initialize_base_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + def _run_force_directed_pre_optimization(self): + """ + Applies multiple force-directed relaxation configurations and selects +- the one yielding the highest sum of radii (Recommendation 4). ++ the one yielding the highest sum of radii (Recommendation 5). + """ + initial_base_centers = self._initialize_base_centers() + best_pre_opt_centers = initial_base_centers.copy() + best_pre_opt_sum_radii = 0.0 + + # Define multiple parameter sets for F-D relaxation to explore different initial states + param_sets = [ + # Mild-aggressive + {'iterations': 500, 'step_size': 0.001, 'repulsion_strength': 0.01, + 'repulsion_threshold': 0.18, 'boundary_strength': 0.05, 'boundary_margin': 0.03}, + # More aggressive (from high-performing G169) + {'iterations': 800, 'step_size': 0.0015, 'repulsion_strength': 0.015, + 'repulsion_threshold': 0.22, 'boundary_strength': 0.08, 'boundary_margin': 0.03}, + # Balanced + {'iterations': 600, 'step_size': 0.0012, 'repulsion_strength': 0.012, + 'repulsion_threshold': 0.20, 'boundary_strength': 0.06, 'boundary_margin': 0.03}, + # Slightly denser (reduced repulsion threshold) + {'iterations': 700, 'step_size': 0.0013, 'repulsion_strength': 0.011, + 'repulsion_threshold': 0.19, 'boundary_strength': 0.055, 'boundary_margin': 0.03}, ++ # Even more aggressive - designed to spread out widely and test boundaries ++ {'iterations': 900, 'step_size': 0.002, 'repulsion_strength': 0.02, ++ 'repulsion_threshold': 0.25, 'boundary_strength': 0.1, 'boundary_margin': 0.02}, + ] + + for params in param_sets: + relaxed_centers = apply_force_directed_relaxation(initial_base_centers.copy(), **params) + radii = compute_max_radii(relaxed_centers) + current_sum_radii = np.sum(radii) + if current_sum_radii > best_pre_opt_sum_radii: + best_pre_opt_sum_radii = current_sum_radii + best_pre_opt_centers = relaxed_centers.copy() + + self.centers = best_pre_opt_centers + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + return self.centers, self.radii, self.sum_radii + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, +- and local crowding (Recommendation 2). ++ and local crowding. + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 +- normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) ++ normalized_crowding = crowding_metric / max_crowwing if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 + + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation. + """ + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r +- perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 ++ # Increased multiplier for more aggressive movement of small circles ++ perturb_factor = 1.0 + (1.0 - relative_radius) * 2.5 + return global_perturb_strength * perturb_factor + +- def _generate_neighbor_state(self, current_centers, current_radii, global_perturb_strength, SA_iteration, total_SA_iterations): ++ def _generate_neighbor_state(self, current_centers, current_radii, global_perturb_strength, SA_iteration, total_SA_iterations, cluster_perturb_prob): + """ + Generates a new candidate state by perturbing one or more circles. +- Combines single-circle perturbation with multi-modal cluster perturbation (Recommendation 3). ++ Combines single-circle perturbation with multi-modal cluster perturbation (Recommendation 2). + """ + candidate_centers = current_centers.copy() + +- # Determine adaptive compute_max_radii iterations (Recommendation 5) ++ # Determine adaptive compute_max_radii iterations (Recommendation 4 based on iteration progress) + min_radii_iter = 100 +- max_radii_iter = 750 ++ max_radii_iter = 1000 # Increased max_radii_iter for finer tuning later in the SA process + current_radii_iterations = int(min_radii_iter + (max_radii_iter - min_radii_iter) * (SA_iteration / total_SA_iterations)) +- if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration +- +- # Multi-modal perturbation choice (Recommendation 3) +- # With a low probability, perturb a cluster instead of a single circle +- if np.random.rand() < 0.15: # Increased chance for cluster perturbation to 15% +- circle_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster ++ if current_radii_iterations < 1: current_radii_iterations = 1 ++ ++ # Multi-modal perturbation choice (Recommendation 1 part - fixed probability for now) ++ if np.random.rand() < cluster_perturb_prob: ++ primary_idx = np.random.choice(self.n) + + all_indices = np.arange(self.n) +- other_indices = np.delete(all_indices, circle_idx) +- ++ other_indices = np.delete(all_indices, primary_idx) ++ ++ cluster_indices = [primary_idx] + if len(other_indices) > 0: +- distances = np.linalg.norm(current_centers[circle_idx] - current_centers[other_indices], axis=1) +- sorted_neighbor_indices = other_indices[np.argsort(distances)] +- +- cluster_indices = [circle_idx] +- num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors +- for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): +- cluster_indices.append(sorted_neighbor_indices[i]) +- +- # Apply a coordinated, smaller displacement to the cluster +- eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) +- cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move +- +- # Generate a single random direction for the entire cluster ++ # Define cluster by distance threshold, not just N closest (Recommendation 2) ++ primary_r = current_radii[primary_idx] ++ # Heuristic: include circles whose centers are within 2.8 times the primary's radius ++ # This aims to select circles that are "interacting" or close-packed ++ cluster_distance_threshold = primary_r * 2.8 ++ ++ distances_to_primary = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) ++ close_neighbor_indices = other_indices[distances_to_primary < cluster_distance_threshold] ++ ++ # Add a few close neighbors to the cluster, ensuring we don't try to pick more than available ++ num_potential_to_add = len(close_neighbor_indices) ++ if num_potential_to_add > 0: ++ num_to_add = np.random.randint(0, min(num_potential_to_add, 3)) # Add 0, 1, or 2 neighbors ++ if num_to_add > 0: ++ cluster_indices.extend(np.random.choice(close_neighbor_indices, size=num_to_add, replace=False)) ++ ++ cluster_indices = list(np.unique(cluster_indices)) # Ensure uniqueness ++ ++ if cluster_indices: ++ # Apply a coordinated displacement to the cluster. Use full effective perturb strength for more impact. ++ eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) ++ cluster_displacement_magnitude = eff_perturb ++ + angle = np.random.uniform(0, 2 * np.pi) +- direction = np.array([np.cos(angle), np.sin(angle)]) ++ direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) +- else: # Fallback to single circle if no neighbors for cluster ++ else: # Fallback to single circle if cluster logic yields no suitable candidates (unlikely if primary is always included) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + return candidate_centers, candidate_radii, candidate_sum_radii + + class SimulatedAnnealingOptimizer: + """ + Generic Simulated Annealing optimizer. + It takes a problem instance that defines initialization, evaluation, + and neighbor generation. + """ + def __init__(self, problem, total_iterations, T_initial, T_final, + initial_perturb_base, final_perturb, max_no_improvement_steps, +- stagnation_boost_duration, stagnation_aggressive_perturb_multiplier): ++ stagnation_boost_duration, stagnation_aggressive_perturb_multiplier, ++ permanent_boost_decay_factor, temp_reheat_factor, cluster_perturb_prob): + + self.problem = problem + self.total_iterations = total_iterations + self.T_initial = T_initial + self.T_final = T_final + self.initial_perturb_base = initial_perturb_base + self.final_perturb = final_perturb + self.max_no_improvement_steps = max_no_improvement_steps + self.stagnation_boost_duration = stagnation_boost_duration + self.stagnation_aggressive_perturb_multiplier = stagnation_aggressive_perturb_multiplier ++ self.permanent_boost_decay_factor = permanent_boost_decay_factor # New parameter for dynamic permanent boost ++ self.temp_reheat_factor = temp_reheat_factor # New parameter for temperature reheat ++ self.cluster_perturb_prob = cluster_perturb_prob # New parameter for cluster perturbation probability + + self.best_centers = None + self.best_radii = None + self.best_sum_radii = -np.inf + + def run(self): + """ + Executes the Simulated Annealing process. + """ + # Initial state from the problem's pre-optimization + current_centers, current_radii, current_sum_radii = self.problem.centers, self.problem.radii, self.problem.sum_radii + + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + self.best_sum_radii = current_sum_radii + + no_improvement_count = 0 + current_initial_perturb = self.initial_perturb_base + stagnation_boost_active_counter = 0 + + for iteration in range(self.total_iterations): + # Annealing schedules ++ # Global perturbation strength decays from current_initial_perturb (potentially boosted) to final_perturb + global_perturb_strength = current_initial_perturb * (1 - iteration / self.total_iterations) + self.final_perturb * (iteration / self.total_iterations) + +- # Apply temporary aggressive perturbation if in stagnation escape (Recommendation 1) ++ # Apply temporary aggressive perturbation if in stagnation escape (Recommendation 3) + if stagnation_boost_active_counter > 0: + global_perturb_strength *= self.stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + ++ # Base temperature decays exponentially + temperature = self.T_initial * (self.T_final / self.T_initial)**(iteration / self.total_iterations) ++ ++ # Apply temporary temperature reheat during stagnation escape (Recommendation 3) ++ if stagnation_boost_active_counter > 0: ++ temperature *= self.temp_reheat_factor + + # Generate candidate state using problem's specific method + candidate_centers, candidate_radii, candidate_sum_radii = self.problem._generate_neighbor_state( +- current_centers, current_radii, global_perturb_strength, iteration, self.total_iterations ++ current_centers, current_radii, global_perturb_strength, iteration, self.total_iterations, self.cluster_perturb_prob + ) + + # Simulated Annealing acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + delta = candidate_sum_radii - current_sum_radii +- acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 ++ # Use math.exp for scalar calculation ++ acceptance_prob = math.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + +- # Update best solution and manage stagnation (Recommendation 1) ++ # Update best solution and manage stagnation (Recommendation 3) + if current_sum_radii > self.best_sum_radii: + self.best_sum_radii = current_sum_radii + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + no_improvement_count = 0 + elif not accepted: + no_improvement_count += 1 + if no_improvement_count > self.max_no_improvement_steps: +- current_initial_perturb *= 1.1 # Small permanent boost to exploration potential ++ # Apply dynamic permanent boost to exploration potential ++ # Larger boost factor earlier, decaying towards the end of SA ++ dynamic_permanent_boost = self.permanent_boost_decay_factor * (1 - iteration / self.total_iterations) ++ current_initial_perturb *= (1 + dynamic_permanent_boost) + stagnation_boost_active_counter = self.stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return self.best_centers, self.best_radii + + + def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePackingProblem and runs SimulatedAnnealingOptimizer. + """ + n_circles = 26 + problem = CirclePackingProblem(n_circles) + +- # Pre-optimization phase (Recommendation 4) ++ # Pre-optimization phase (Recommendation 5) + # This sets problem.centers, problem.radii, problem.sum_radii + problem._run_force_directed_pre_optimization() + + # Simulated Annealing parameters + sa_params = { +- 'total_iterations': 25000, +- 'T_initial': 0.4, +- 'T_final': 1e-9, +- 'initial_perturb_base': 0.06, ++ 'total_iterations': 35000, # Increased iterations for more thorough search ++ 'T_initial': 0.5, # Increased initial temperature for broader exploration ++ 'T_final': 1e-10, # Slightly lower final temperature for finer convergence ++ 'initial_perturb_base': 0.07, # Increased initial perturbation strength + 'final_perturb': 0.0001, + 'max_no_improvement_steps': 1000, + 'stagnation_boost_duration': 200, +- 'stagnation_aggressive_perturb_multiplier': 2.0 ++ 'stagnation_aggressive_perturb_multiplier': 2.5, # Increased aggressive multiplier during escape ++ 'permanent_boost_decay_factor': 0.15, # New: Dynamic permanent boost for exploration (Recommendation 3) ++ 'temp_reheat_factor': 1.5, # New: Temporary temperature reheat during stagnation (Recommendation 3) ++ 'cluster_perturb_prob': 0.2 # Increased probability for cluster perturbations (Recommendation 1) + } + + optimizer = SimulatedAnnealingOptimizer(problem, **sa_params) + return optimizer.run() +- + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/main.py new file mode 100644 index 0000000000000000000000000000000000000000..3ec9a86e17cd1eb7d6bc32fa17d27793abd56ac0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/main.py @@ -0,0 +1,398 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math # Needed for math.exp + +# Utility functions (kept outside classes as they are general calculations) +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + +class CirclePackingProblem: + """ + Encapsulates the definition of the circle packing problem for n circles + within a unit square, including initialization, evaluation, and perturbation + strategies. + """ + def __init__(self, n): + self.n = n + self.centers = None + self.radii = None + self.sum_radii = 0.0 + + def _initialize_base_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + def _run_force_directed_pre_optimization(self): + """ + Applies multiple force-directed relaxation configurations and selects + the one yielding the highest sum of radii (Recommendation 5). + """ + initial_base_centers = self._initialize_base_centers() + best_pre_opt_centers = initial_base_centers.copy() + best_pre_opt_sum_radii = 0.0 + + # Define multiple parameter sets for F-D relaxation to explore different initial states + param_sets = [ + # Mild-aggressive + {'iterations': 500, 'step_size': 0.001, 'repulsion_strength': 0.01, + 'repulsion_threshold': 0.18, 'boundary_strength': 0.05, 'boundary_margin': 0.03}, + # More aggressive (from high-performing G169) + {'iterations': 800, 'step_size': 0.0015, 'repulsion_strength': 0.015, + 'repulsion_threshold': 0.22, 'boundary_strength': 0.08, 'boundary_margin': 0.03}, + # Balanced + {'iterations': 600, 'step_size': 0.0012, 'repulsion_strength': 0.012, + 'repulsion_threshold': 0.20, 'boundary_strength': 0.06, 'boundary_margin': 0.03}, + # Slightly denser (reduced repulsion threshold) + {'iterations': 700, 'step_size': 0.0013, 'repulsion_strength': 0.011, + 'repulsion_threshold': 0.19, 'boundary_strength': 0.055, 'boundary_margin': 0.03}, + # Even more aggressive - designed to spread out widely and test boundaries + {'iterations': 900, 'step_size': 0.002, 'repulsion_strength': 0.02, + 'repulsion_threshold': 0.25, 'boundary_strength': 0.1, 'boundary_margin': 0.02}, + ] + + for params in param_sets: + relaxed_centers = apply_force_directed_relaxation(initial_base_centers.copy(), **params) + radii = compute_max_radii(relaxed_centers) + current_sum_radii = np.sum(radii) + if current_sum_radii > best_pre_opt_sum_radii: + best_pre_opt_sum_radii = current_sum_radii + best_pre_opt_centers = relaxed_centers.copy() + + self.centers = best_pre_opt_centers + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + return self.centers, self.radii, self.sum_radii + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding. + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 + normalized_crowding = crowding_metric / max_crowwing if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 + + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation. + """ + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + # Increased multiplier for more aggressive movement of small circles + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.5 + return global_perturb_strength * perturb_factor + + def _generate_neighbor_state(self, current_centers, current_radii, global_perturb_strength, SA_iteration, total_SA_iterations, cluster_perturb_prob): + """ + Generates a new candidate state by perturbing one or more circles. + Combines single-circle perturbation with multi-modal cluster perturbation (Recommendation 2). + """ + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (Recommendation 4 based on iteration progress) + min_radii_iter = 100 + max_radii_iter = 1000 # Increased max_radii_iter for finer tuning later in the SA process + current_radii_iterations = int(min_radii_iter + (max_radii_iter - min_radii_iter) * (SA_iteration / total_SA_iterations)) + if current_radii_iterations < 1: current_radii_iterations = 1 + + # Multi-modal perturbation choice (Recommendation 1 part - fixed probability for now) + if np.random.rand() < cluster_perturb_prob: + primary_idx = np.random.choice(self.n) + + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + cluster_indices = [primary_idx] + if len(other_indices) > 0: + # Define cluster by distance threshold, not just N closest (Recommendation 2) + primary_r = current_radii[primary_idx] + # Heuristic: include circles whose centers are within 2.8 times the primary's radius + # This aims to select circles that are "interacting" or close-packed + cluster_distance_threshold = primary_r * 2.8 + + distances_to_primary = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + close_neighbor_indices = other_indices[distances_to_primary < cluster_distance_threshold] + + # Add a few close neighbors to the cluster, ensuring we don't try to pick more than available + num_potential_to_add = len(close_neighbor_indices) + if num_potential_to_add > 0: + num_to_add = np.random.randint(0, min(num_potential_to_add, 3)) # Add 0, 1, or 2 neighbors + if num_to_add > 0: + cluster_indices.extend(np.random.choice(close_neighbor_indices, size=num_to_add, replace=False)) + + cluster_indices = list(np.unique(cluster_indices)) # Ensure uniqueness + + if cluster_indices: + # Apply a coordinated displacement to the cluster. Use full effective perturb strength for more impact. + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) + cluster_displacement_magnitude = eff_perturb + + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle if cluster logic yields no suitable candidates (unlikely if primary is always included) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + return candidate_centers, candidate_radii, candidate_sum_radii + +class SimulatedAnnealingOptimizer: + """ + Generic Simulated Annealing optimizer. + It takes a problem instance that defines initialization, evaluation, + and neighbor generation. + """ + def __init__(self, problem, total_iterations, T_initial, T_final, + initial_perturb_base, final_perturb, max_no_improvement_steps, + stagnation_boost_duration, stagnation_aggressive_perturb_multiplier, + permanent_boost_decay_factor, temp_reheat_factor, cluster_perturb_prob): + + self.problem = problem + self.total_iterations = total_iterations + self.T_initial = T_initial + self.T_final = T_final + self.initial_perturb_base = initial_perturb_base + self.final_perturb = final_perturb + self.max_no_improvement_steps = max_no_improvement_steps + self.stagnation_boost_duration = stagnation_boost_duration + self.stagnation_aggressive_perturb_multiplier = stagnation_aggressive_perturb_multiplier + self.permanent_boost_decay_factor = permanent_boost_decay_factor # New parameter for dynamic permanent boost + self.temp_reheat_factor = temp_reheat_factor # New parameter for temperature reheat + self.cluster_perturb_prob = cluster_perturb_prob # New parameter for cluster perturbation probability + + self.best_centers = None + self.best_radii = None + self.best_sum_radii = -np.inf + + def run(self): + """ + Executes the Simulated Annealing process. + """ + # Initial state from the problem's pre-optimization + current_centers, current_radii, current_sum_radii = self.problem.centers, self.problem.radii, self.problem.sum_radii + + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + self.best_sum_radii = current_sum_radii + + no_improvement_count = 0 + current_initial_perturb = self.initial_perturb_base + stagnation_boost_active_counter = 0 + + for iteration in range(self.total_iterations): + # Annealing schedules + # Global perturbation strength decays from current_initial_perturb (potentially boosted) to final_perturb + global_perturb_strength = current_initial_perturb * (1 - iteration / self.total_iterations) + self.final_perturb * (iteration / self.total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape (Recommendation 3) + if stagnation_boost_active_counter > 0: + global_perturb_strength *= self.stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + # Base temperature decays exponentially + temperature = self.T_initial * (self.T_final / self.T_initial)**(iteration / self.total_iterations) + + # Apply temporary temperature reheat during stagnation escape (Recommendation 3) + if stagnation_boost_active_counter > 0: + temperature *= self.temp_reheat_factor + + # Generate candidate state using problem's specific method + candidate_centers, candidate_radii, candidate_sum_radii = self.problem._generate_neighbor_state( + current_centers, current_radii, global_perturb_strength, iteration, self.total_iterations, self.cluster_perturb_prob + ) + + # Simulated Annealing acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + delta = candidate_sum_radii - current_sum_radii + # Use math.exp for scalar calculation + acceptance_prob = math.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation (Recommendation 3) + if current_sum_radii > self.best_sum_radii: + self.best_sum_radii = current_sum_radii + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + no_improvement_count = 0 + elif not accepted: + no_improvement_count += 1 + if no_improvement_count > self.max_no_improvement_steps: + # Apply dynamic permanent boost to exploration potential + # Larger boost factor earlier, decaying towards the end of SA + dynamic_permanent_boost = self.permanent_boost_decay_factor * (1 - iteration / self.total_iterations) + current_initial_perturb *= (1 + dynamic_permanent_boost) + stagnation_boost_active_counter = self.stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return self.best_centers, self.best_radii + + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePackingProblem and runs SimulatedAnnealingOptimizer. + """ + n_circles = 26 + problem = CirclePackingProblem(n_circles) + + # Pre-optimization phase (Recommendation 5) + # This sets problem.centers, problem.radii, problem.sum_radii + problem._run_force_directed_pre_optimization() + + # Simulated Annealing parameters + sa_params = { + 'total_iterations': 35000, # Increased iterations for more thorough search + 'T_initial': 0.5, # Increased initial temperature for broader exploration + 'T_final': 1e-10, # Slightly lower final temperature for finer convergence + 'initial_perturb_base': 0.07, # Increased initial perturbation strength + 'final_perturb': 0.0001, + 'max_no_improvement_steps': 1000, + 'stagnation_boost_duration': 200, + 'stagnation_aggressive_perturb_multiplier': 2.5, # Increased aggressive multiplier during escape + 'permanent_boost_decay_factor': 0.15, # New: Dynamic permanent boost for exploration (Recommendation 3) + 'temp_reheat_factor': 1.5, # New: Temporary temperature reheat during stagnation (Recommendation 3) + 'cluster_perturb_prob': 0.2 # Increased probability for cluster perturbations (Recommendation 1) + } + + optimizer = SimulatedAnnealingOptimizer(problem, **sa_params) + return optimizer.run() +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/original.py new file mode 100644 index 0000000000000000000000000000000000000000..a9e00878b90e1ac9653142eaaa1af28c2bbce51a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/original.py @@ -0,0 +1,367 @@ +# EVOLVE-BLOCK-START +import numpy as np + +# Utility functions (kept outside classes as they are general calculations) +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + +class CirclePackingProblem: + """ + Encapsulates the definition of the circle packing problem for n circles + within a unit square, including initialization, evaluation, and perturbation + strategies. + """ + def __init__(self, n): + self.n = n + self.centers = None + self.radii = None + self.sum_radii = 0.0 + + def _initialize_base_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + def _run_force_directed_pre_optimization(self): + """ + Applies multiple force-directed relaxation configurations and selects + the one yielding the highest sum of radii (Recommendation 4). + """ + initial_base_centers = self._initialize_base_centers() + best_pre_opt_centers = initial_base_centers.copy() + best_pre_opt_sum_radii = 0.0 + + # Define multiple parameter sets for F-D relaxation to explore different initial states + param_sets = [ + # Mild-aggressive + {'iterations': 500, 'step_size': 0.001, 'repulsion_strength': 0.01, + 'repulsion_threshold': 0.18, 'boundary_strength': 0.05, 'boundary_margin': 0.03}, + # More aggressive (from high-performing G169) + {'iterations': 800, 'step_size': 0.0015, 'repulsion_strength': 0.015, + 'repulsion_threshold': 0.22, 'boundary_strength': 0.08, 'boundary_margin': 0.03}, + # Balanced + {'iterations': 600, 'step_size': 0.0012, 'repulsion_strength': 0.012, + 'repulsion_threshold': 0.20, 'boundary_strength': 0.06, 'boundary_margin': 0.03}, + # Slightly denser (reduced repulsion threshold) + {'iterations': 700, 'step_size': 0.0013, 'repulsion_strength': 0.011, + 'repulsion_threshold': 0.19, 'boundary_strength': 0.055, 'boundary_margin': 0.03}, + ] + + for params in param_sets: + relaxed_centers = apply_force_directed_relaxation(initial_base_centers.copy(), **params) + radii = compute_max_radii(relaxed_centers) + current_sum_radii = np.sum(radii) + if current_sum_radii > best_pre_opt_sum_radii: + best_pre_opt_sum_radii = current_sum_radii + best_pre_opt_centers = relaxed_centers.copy() + + self.centers = best_pre_opt_centers + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + return self.centers, self.radii, self.sum_radii + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding (Recommendation 2). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 + + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation. + """ + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 + return global_perturb_strength * perturb_factor + + def _generate_neighbor_state(self, current_centers, current_radii, global_perturb_strength, SA_iteration, total_SA_iterations): + """ + Generates a new candidate state by perturbing one or more circles. + Combines single-circle perturbation with multi-modal cluster perturbation (Recommendation 3). + """ + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (Recommendation 5) + min_radii_iter = 100 + max_radii_iter = 750 + current_radii_iterations = int(min_radii_iter + (max_radii_iter - min_radii_iter) * (SA_iteration / total_SA_iterations)) + if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration + + # Multi-modal perturbation choice (Recommendation 3) + # With a low probability, perturb a cluster instead of a single circle + if np.random.rand() < 0.15: # Increased chance for cluster perturbation to 15% + circle_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster + + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, circle_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[circle_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [circle_idx] + num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + # Apply a coordinated, smaller displacement to the cluster + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move + + # Generate a single random direction for the entire cluster + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([np.cos(angle), np.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle if no neighbors for cluster + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + return candidate_centers, candidate_radii, candidate_sum_radii + +class SimulatedAnnealingOptimizer: + """ + Generic Simulated Annealing optimizer. + It takes a problem instance that defines initialization, evaluation, + and neighbor generation. + """ + def __init__(self, problem, total_iterations, T_initial, T_final, + initial_perturb_base, final_perturb, max_no_improvement_steps, + stagnation_boost_duration, stagnation_aggressive_perturb_multiplier): + + self.problem = problem + self.total_iterations = total_iterations + self.T_initial = T_initial + self.T_final = T_final + self.initial_perturb_base = initial_perturb_base + self.final_perturb = final_perturb + self.max_no_improvement_steps = max_no_improvement_steps + self.stagnation_boost_duration = stagnation_boost_duration + self.stagnation_aggressive_perturb_multiplier = stagnation_aggressive_perturb_multiplier + + self.best_centers = None + self.best_radii = None + self.best_sum_radii = -np.inf + + def run(self): + """ + Executes the Simulated Annealing process. + """ + # Initial state from the problem's pre-optimization + current_centers, current_radii, current_sum_radii = self.problem.centers, self.problem.radii, self.problem.sum_radii + + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + self.best_sum_radii = current_sum_radii + + no_improvement_count = 0 + current_initial_perturb = self.initial_perturb_base + stagnation_boost_active_counter = 0 + + for iteration in range(self.total_iterations): + # Annealing schedules + global_perturb_strength = current_initial_perturb * (1 - iteration / self.total_iterations) + self.final_perturb * (iteration / self.total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape (Recommendation 1) + if stagnation_boost_active_counter > 0: + global_perturb_strength *= self.stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + temperature = self.T_initial * (self.T_final / self.T_initial)**(iteration / self.total_iterations) + + # Generate candidate state using problem's specific method + candidate_centers, candidate_radii, candidate_sum_radii = self.problem._generate_neighbor_state( + current_centers, current_radii, global_perturb_strength, iteration, self.total_iterations + ) + + # Simulated Annealing acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + delta = candidate_sum_radii - current_sum_radii + acceptance_prob = np.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation (Recommendation 1) + if current_sum_radii > self.best_sum_radii: + self.best_sum_radii = current_sum_radii + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + no_improvement_count = 0 + elif not accepted: + no_improvement_count += 1 + if no_improvement_count > self.max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential + stagnation_boost_active_counter = self.stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return self.best_centers, self.best_radii + + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePackingProblem and runs SimulatedAnnealingOptimizer. + """ + n_circles = 26 + problem = CirclePackingProblem(n_circles) + + # Pre-optimization phase (Recommendation 4) + # This sets problem.centers, problem.radii, problem.sum_radii + problem._run_force_directed_pre_optimization() + + # Simulated Annealing parameters + sa_params = { + 'total_iterations': 25000, + 'T_initial': 0.4, + 'T_final': 1e-9, + 'initial_perturb_base': 0.06, + 'final_perturb': 0.0001, + 'max_no_improvement_steps': 1000, + 'stagnation_boost_duration': 200, + 'stagnation_aggressive_perturb_multiplier': 2.0 + } + + optimizer = SimulatedAnnealingOptimizer(problem, **sa_params) + return optimizer.run() + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..027a552d5315a985c7c7d0351cd2b69fd9a26569 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": false, + "error": "name 'max_crowwing' is not defined" +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..d90ca4cd4409cb12ed673b1ec64fd0d7d1924617 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/job_log.out @@ -0,0 +1,14 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_194/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_194/results +Evaluation error: name 'max_crowwing' is not defined +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/metrics.json +Evaluation or Validation failed: name 'max_crowwing' is not defined +Metrics: + combined_score: 0.0 + execution_time_mean: 0.0 + execution_time_std: 0.0 + num_successful_runs: 0 + num_valid_runs: 0 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..fec2021a6a036637c9d3049ae9778c77cef78421 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/results/metrics.json @@ -0,0 +1,9 @@ +{ + "combined_score": 0.0, + "execution_time_mean": 0.0, + "execution_time_std": 0.0, + "num_successful_runs": 0, + "num_valid_runs": 0, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..cc417d01e48ff80d78b0a0d81ae61fa6e03b77a2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_194/rewrite.txt @@ -0,0 +1,388 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math # Needed for math.exp + +# Utility functions (kept outside classes as they are general calculations) +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + +class CirclePackingProblem: + """ + Encapsulates the definition of the circle packing problem for n circles + within a unit square, including initialization, evaluation, and perturbation + strategies. + """ + def __init__(self, n): + self.n = n + self.centers = None + self.radii = None + self.sum_radii = 0.0 + + def _initialize_base_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void. + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) + amplitude = 0.06 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((self.n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + def _run_force_directed_pre_optimization(self): + """ + Applies multiple force-directed relaxation configurations and selects + the one yielding the highest sum of radii (Recommendation 5). + """ + initial_base_centers = self._initialize_base_centers() + best_pre_opt_centers = initial_base_centers.copy() + best_pre_opt_sum_radii = 0.0 + + # Define multiple parameter sets for F-D relaxation to explore different initial states + param_sets = [ + # Mild-aggressive + {'iterations': 500, 'step_size': 0.001, 'repulsion_strength': 0.01, + 'repulsion_threshold': 0.18, 'boundary_strength': 0.05, 'boundary_margin': 0.03}, + # More aggressive (from high-performing G169) + {'iterations': 800, 'step_size': 0.0015, 'repulsion_strength': 0.015, + 'repulsion_threshold': 0.22, 'boundary_strength': 0.08, 'boundary_margin': 0.03}, + # Balanced + {'iterations': 600, 'step_size': 0.0012, 'repulsion_strength': 0.012, + 'repulsion_threshold': 0.20, 'boundary_strength': 0.06, 'boundary_margin': 0.03}, + # Slightly denser (reduced repulsion threshold) + {'iterations': 700, 'step_size': 0.0013, 'repulsion_strength': 0.011, + 'repulsion_threshold': 0.19, 'boundary_strength': 0.055, 'boundary_margin': 0.03}, + # Even more aggressive - designed to spread out widely and test boundaries + {'iterations': 900, 'step_size': 0.002, 'repulsion_strength': 0.02, + 'repulsion_threshold': 0.25, 'boundary_strength': 0.1, 'boundary_margin': 0.02}, + ] + + for params in param_sets: + relaxed_centers = apply_force_directed_relaxation(initial_base_centers.copy(), **params) + radii = compute_max_radii(relaxed_centers) + current_sum_radii = np.sum(radii) + if current_sum_radii > best_pre_opt_sum_radii: + best_pre_opt_sum_radii = current_sum_radii + best_pre_opt_centers = relaxed_centers.copy() + + self.centers = best_pre_opt_centers + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + return self.centers, self.radii, self.sum_radii + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding. + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 + normalized_crowding = crowding_metric / max_crowwing if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 + + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation. + """ + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + # Increased multiplier for more aggressive movement of small circles + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.5 + return global_perturb_strength * perturb_factor + + def _generate_neighbor_state(self, current_centers, current_radii, global_perturb_strength, SA_iteration, total_SA_iterations, cluster_perturb_prob): + """ + Generates a new candidate state by perturbing one or more circles. + Combines single-circle perturbation with multi-modal cluster perturbation (Recommendation 2). + """ + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (Recommendation 4 based on iteration progress) + min_radii_iter = 100 + max_radii_iter = 1000 # Increased max_radii_iter for finer tuning later in the SA process + current_radii_iterations = int(min_radii_iter + (max_radii_iter - min_radii_iter) * (SA_iteration / total_SA_iterations)) + if current_radii_iterations < 1: current_radii_iterations = 1 + + # Multi-modal perturbation choice (Recommendation 1 part - fixed probability for now) + if np.random.rand() < cluster_perturb_prob: + primary_idx = np.random.choice(self.n) + + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + cluster_indices = [primary_idx] + if len(other_indices) > 0: + # Define cluster by distance threshold, not just N closest (Recommendation 2) + primary_r = current_radii[primary_idx] + # Heuristic: include circles whose centers are within 2.8 times the primary's radius + # This aims to select circles that are "interacting" or close-packed + cluster_distance_threshold = primary_r * 2.8 + + distances_to_primary = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + close_neighbor_indices = other_indices[distances_to_primary < cluster_distance_threshold] + + # Add a few close neighbors to the cluster, ensuring we don't try to pick more than available + num_potential_to_add = len(close_neighbor_indices) + if num_potential_to_add > 0: + num_to_add = np.random.randint(0, min(num_potential_to_add, 3)) # Add 0, 1, or 2 neighbors + if num_to_add > 0: + cluster_indices.extend(np.random.choice(close_neighbor_indices, size=num_to_add, replace=False)) + + cluster_indices = list(np.unique(cluster_indices)) # Ensure uniqueness + + if cluster_indices: + # Apply a coordinated displacement to the cluster. Use full effective perturb strength for more impact. + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) + cluster_displacement_magnitude = eff_perturb + + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle if cluster logic yields no suitable candidates (unlikely if primary is always included) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + return candidate_centers, candidate_radii, candidate_sum_radii + +class SimulatedAnnealingOptimizer: + """ + Generic Simulated Annealing optimizer. + It takes a problem instance that defines initialization, evaluation, + and neighbor generation. + """ + def __init__(self, problem, total_iterations, T_initial, T_final, + initial_perturb_base, final_perturb, max_no_improvement_steps, + stagnation_boost_duration, stagnation_aggressive_perturb_multiplier, + permanent_boost_decay_factor, temp_reheat_factor, cluster_perturb_prob): + + self.problem = problem + self.total_iterations = total_iterations + self.T_initial = T_initial + self.T_final = T_final + self.initial_perturb_base = initial_perturb_base + self.final_perturb = final_perturb + self.max_no_improvement_steps = max_no_improvement_steps + self.stagnation_boost_duration = stagnation_boost_duration + self.stagnation_aggressive_perturb_multiplier = stagnation_aggressive_perturb_multiplier + self.permanent_boost_decay_factor = permanent_boost_decay_factor # New parameter for dynamic permanent boost + self.temp_reheat_factor = temp_reheat_factor # New parameter for temperature reheat + self.cluster_perturb_prob = cluster_perturb_prob # New parameter for cluster perturbation probability + + self.best_centers = None + self.best_radii = None + self.best_sum_radii = -np.inf + + def run(self): + """ + Executes the Simulated Annealing process. + """ + # Initial state from the problem's pre-optimization + current_centers, current_radii, current_sum_radii = self.problem.centers, self.problem.radii, self.problem.sum_radii + + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + self.best_sum_radii = current_sum_radii + + no_improvement_count = 0 + current_initial_perturb = self.initial_perturb_base + stagnation_boost_active_counter = 0 + + for iteration in range(self.total_iterations): + # Annealing schedules + # Global perturbation strength decays from current_initial_perturb (potentially boosted) to final_perturb + global_perturb_strength = current_initial_perturb * (1 - iteration / self.total_iterations) + self.final_perturb * (iteration / self.total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape (Recommendation 3) + if stagnation_boost_active_counter > 0: + global_perturb_strength *= self.stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + # Base temperature decays exponentially + temperature = self.T_initial * (self.T_final / self.T_initial)**(iteration / self.total_iterations) + + # Apply temporary temperature reheat during stagnation escape (Recommendation 3) + if stagnation_boost_active_counter > 0: + temperature *= self.temp_reheat_factor + + # Generate candidate state using problem's specific method + candidate_centers, candidate_radii, candidate_sum_radii = self.problem._generate_neighbor_state( + current_centers, current_radii, global_perturb_strength, iteration, self.total_iterations, self.cluster_perturb_prob + ) + + # Simulated Annealing acceptance criteria + accepted = False + if candidate_sum_radii > current_sum_radii: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + else: + delta = candidate_sum_radii - current_sum_radii + # Use math.exp for scalar calculation + acceptance_prob = math.exp(delta / temperature) if temperature > 0 else 0 + if np.random.rand() < acceptance_prob: + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation (Recommendation 3) + if current_sum_radii > self.best_sum_radii: + self.best_sum_radii = current_sum_radii + self.best_centers = current_centers.copy() + self.best_radii = current_radii.copy() + no_improvement_count = 0 + elif not accepted: + no_improvement_count += 1 + if no_improvement_count > self.max_no_improvement_steps: + # Apply dynamic permanent boost to exploration potential + # Larger boost factor earlier, decaying towards the end of SA + dynamic_permanent_boost = self.permanent_boost_decay_factor * (1 - iteration / self.total_iterations) + current_initial_perturb *= (1 + dynamic_permanent_boost) + stagnation_boost_active_counter = self.stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return self.best_centers, self.best_radii + + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePackingProblem and runs SimulatedAnnealingOptimizer. + """ + n_circles = 26 + problem = CirclePackingProblem(n_circles) + + # Pre-optimization phase (Recommendation 5) + # This sets problem.centers, problem.radii, problem.sum_radii + problem._run_force_directed_pre_optimization() + + # Simulated Annealing parameters + sa_params = { + 'total_iterations': 35000, # Increased iterations for more thorough search + 'T_initial': 0.5, # Increased initial temperature for broader exploration + 'T_final': 1e-10, # Slightly lower final temperature for finer convergence + 'initial_perturb_base': 0.07, # Increased initial perturbation strength + 'final_perturb': 0.0001, + 'max_no_improvement_steps': 1000, + 'stagnation_boost_duration': 200, + 'stagnation_aggressive_perturb_multiplier': 2.5, # Increased aggressive multiplier during escape + 'permanent_boost_decay_factor': 0.15, # New: Dynamic permanent boost for exploration (Recommendation 3) + 'temp_reheat_factor': 1.5, # New: Temporary temperature reheat during stagnation (Recommendation 3) + 'cluster_perturb_prob': 0.2 # Increased probability for cluster perturbations (Recommendation 1) + } + + optimizer = SimulatedAnnealingOptimizer(problem, **sa_params) + return optimizer.run() \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..19bafb30abd133e560bd88bb087f974c1ee714f2 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..1463a0423061aac5b29622b2f378d79c6616a189 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/edit.diff @@ -0,0 +1,327 @@ +--- a/original.py ++++ b/original.py +@@ -1,275 +1,287 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + + def _generate_void_config(n, void_center, amplitude, sigma): + """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + + def relaxation_stage(centers, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation (jiggle) phase.""" + relaxed_centers = centers.copy() + for _ in range(iters): + diff = relaxed_centers[:, np.newaxis, :] - relaxed_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, relaxed_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, relaxed_centers[:, 1] - (1 - boundary_margin)) + + relaxed_centers += step_size * forces + relaxed_centers = np.clip(relaxed_centers, 0.0, 1.0) + return relaxed_centers + + def _select_circle_context_aware(n, current_radii, current_centers): + """Intelligently selects a circle to perturb based on radius, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(n) + for i in range(n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(n, p=selection_probs) + + def _adaptive_perturbation_strength(base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + + def annealing_stage(centers, n): + """Performs the main simulated annealing optimization stage.""" + current_centers = centers.copy() + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_sum_radii = current_sum_radii + + # SA Parameters +- total_iterations = 20000 +- initial_temp = 0.0008 +- final_temp = 1e-9 +- initial_perturb_strength = 0.035 ++ total_iterations = 35000 ++ initial_temp = 0.001 ++ final_temp = 1e-10 ++ initial_perturb_strength = 0.04 + final_perturb_strength = 0.0001 + + # Stagnation Escape Parameters + stagnation_counter = 0 +- stagnation_threshold = 800 ++ stagnation_threshold = 1500 + perturb_boost = 1.0 +- boost_factor = 3.0 +- boost_decay = 0.98 +- +- # New parameters for swap perturbation, integrated with stagnation escape +- base_swap_prob = 0.1 +- swap_prob_boost = 1.0 +- swap_prob_boost_factor = 3.0 # Temporarily triple the swap probability +- swap_prob_boost_decay = 0.98 ++ boost_factor = 4.0 ++ boost_decay = 0.97 ++ temp_reheat_factor = 0.5 ++ ++ # Perturbation move probabilities ++ swap_prob = 0.10 ++ cluster_prob = 0.15 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + + # Annealing schedules + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + +- # Stagnation escape: boost perturbation, swap prob, and reheat temperature ++ # Stagnation escape: boost perturbation and reheat temperature + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor +- swap_prob_boost = swap_prob_boost_factor +- temp = temp_schedule + initial_temp * 0.4 # Reheat ++ temp = temp_schedule + initial_temp * temp_reheat_factor # Reheat + stagnation_counter = 0 + else: + temp = temp_schedule + + candidate_centers = current_centers.copy() +- +- current_swap_prob = np.clip(base_swap_prob * swap_prob_boost, 0, 0.5) +- +- if np.random.rand() < current_swap_prob: +- # Swap Perturbation: swap a small circle with a large one ++ rand_val = np.random.rand() ++ ++ if rand_val < swap_prob: ++ # Perturbation 1: Swap small and large circles + sorted_indices = np.argsort(current_radii) + if n > 1: +- num_small = n // 2 +- small_circles_indices = sorted_indices[:num_small] +- large_circles_indices = sorted_indices[num_small:] +- +- if len(small_circles_indices) > 0 and len(large_circles_indices) > 0: +- idx_small = np.random.choice(small_circles_indices) +- idx_large = np.random.choice(large_circles_indices) +- +- # Swap positions ++ num_candidates = max(1, n // 4) ++ idx_small = np.random.choice(sorted_indices[:num_candidates]) ++ idx_large = np.random.choice(sorted_indices[-num_candidates:]) ++ if idx_small != idx_large: + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() ++ ++ elif rand_val < swap_prob + cluster_prob: ++ # Perturbation 2: Cluster move ++ primary_idx = _select_circle_context_aware(n, current_radii, current_centers) ++ distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) ++ distances[primary_idx] = np.inf ++ neighbor_indices = np.argsort(distances)[:2] ++ indices_to_perturb = np.append(neighbor_indices, primary_idx) ++ ++ eff_strength = _adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost * 0.6 ++ displacement = np.random.uniform(-eff_strength, eff_strength, 2) ++ candidate_centers[indices_to_perturb] += displacement ++ candidate_centers[indices_to_perturb] = np.clip(candidate_centers[indices_to_perturb], 0.0, 1.0) ++ + else: +- # Standard Displacement Perturbation ++ # Perturbation 3: Single circle move with Rattler Teleport + circle_idx = _select_circle_context_aware(n, current_radii, current_centers) +- effective_perturb_strength = _adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost +- displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) +- candidate_centers[circle_idx] += displacement +- candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) ++ ++ RATTLE_THRESHOLD = 0.025 ++ RELOCATE_PROB = 0.3 # Probability to teleport a rattler ++ ++ if current_radii[circle_idx] < RATTLE_THRESHOLD and np.random.rand() < RELOCATE_PROB: ++ candidate_centers[circle_idx] = np.random.uniform(0.05, 0.95, 2) ++ else: ++ # Standard displacement ++ effective_perturb_strength = _adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost ++ displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) ++ candidate_centers[circle_idx] += displacement ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay boosts + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay +- if swap_prob_boost > 1.0: +- swap_prob_boost = 1.0 + (swap_prob_boost - 1.0) * swap_prob_boost_decay + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + return best_centers + + def initialization_stage(n): + """Performs a multi-start initialization and selects the best starting point.""" + best_initial_sum_radii = -1.0 + best_initial_centers = None + + # Diverse void configurations to try + void_configs = [ + (np.array([0.4, 0.2]), 0.06), + (np.array([0.2, 0.4]), 0.05), + (np.array([0.6, 0.8]), 0.07), + (np.array([0.8, 0.6]), 0.065), + (np.array([0.5, 0.5]), 0.05), + (np.random.uniform(0.3, 0.7, 2), 0.08), + ] + + for void_center, amplitude in void_configs: + candidate_centers = _generate_void_config(n, void_center, amplitude, sigma=0.15) + + # Settle with a very quick relaxation + relaxed_centers = relaxation_stage( + candidate_centers, iters=150, step_size=0.002, + repulsion_strength=0.02, boundary_strength=0.07, + repulsion_threshold=0.2, boundary_margin=0.04 + ) + candidate_radii = compute_max_radii(relaxed_centers) + candidate_sum_radii = np.sum(candidate_radii) + + if candidate_sum_radii > best_initial_sum_radii: + best_initial_sum_radii = candidate_sum_radii + best_initial_centers = relaxed_centers.copy() + + return best_initial_centers + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a functional, + multi-stage optimization pipeline. + """ + n = 26 + + # Stage 1: Multi-Start Initialization to find a robust starting point + initial_centers = initialization_stage(n) + + # Stage 2: Main Simulated Annealing optimization + # The initial relaxation is now part of the initialization stage, + # so we can directly proceed to annealing. + annealed_centers = annealing_stage(initial_centers, n) + + # Stage 3: Final gentle polish using relaxation + final_centers = relaxation_stage( + annealed_centers, iters=300, step_size=0.0001, + repulsion_strength=0.001, boundary_strength=0.005, + repulsion_threshold=0.18, boundary_margin=0.02 + ) + + # Final evaluation + final_radii = compute_max_radii(final_centers) + annealed_radii = compute_max_radii(annealed_centers) + + # Return the best result between the SA output and the polished version + if np.sum(final_radii) > np.sum(annealed_radii): + return final_centers, final_radii + else: + return annealed_centers, annealed_radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/main.py new file mode 100644 index 0000000000000000000000000000000000000000..fb0926e50ebfefcbb6c72d13ece73e516ddbb652 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/main.py @@ -0,0 +1,287 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +def _generate_void_config(n, void_center, amplitude, sigma): + """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + +def relaxation_stage(centers, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation (jiggle) phase.""" + relaxed_centers = centers.copy() + for _ in range(iters): + diff = relaxed_centers[:, np.newaxis, :] - relaxed_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, relaxed_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, relaxed_centers[:, 1] - (1 - boundary_margin)) + + relaxed_centers += step_size * forces + relaxed_centers = np.clip(relaxed_centers, 0.0, 1.0) + return relaxed_centers + +def _select_circle_context_aware(n, current_radii, current_centers): + """Intelligently selects a circle to perturb based on radius, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(n) + for i in range(n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(n, p=selection_probs) + +def _adaptive_perturbation_strength(base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + +def annealing_stage(centers, n): + """Performs the main simulated annealing optimization stage.""" + current_centers = centers.copy() + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_sum_radii = current_sum_radii + + # SA Parameters + total_iterations = 35000 + initial_temp = 0.001 + final_temp = 1e-10 + initial_perturb_strength = 0.04 + final_perturb_strength = 0.0001 + + # Stagnation Escape Parameters + stagnation_counter = 0 + stagnation_threshold = 1500 + perturb_boost = 1.0 + boost_factor = 4.0 + boost_decay = 0.97 + temp_reheat_factor = 0.5 + + # Perturbation move probabilities + swap_prob = 0.10 + cluster_prob = 0.15 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + + # Annealing schedules + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Stagnation escape: boost perturbation and reheat temperature + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + temp = temp_schedule + initial_temp * temp_reheat_factor # Reheat + stagnation_counter = 0 + else: + temp = temp_schedule + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_prob: + # Perturbation 1: Swap small and large circles + sorted_indices = np.argsort(current_radii) + if n > 1: + num_candidates = max(1, n // 4) + idx_small = np.random.choice(sorted_indices[:num_candidates]) + idx_large = np.random.choice(sorted_indices[-num_candidates:]) + if idx_small != idx_large: + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() + + elif rand_val < swap_prob + cluster_prob: + # Perturbation 2: Cluster move + primary_idx = _select_circle_context_aware(n, current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + + eff_strength = _adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost * 0.6 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement + candidate_centers[indices_to_perturb] = np.clip(candidate_centers[indices_to_perturb], 0.0, 1.0) + + else: + # Perturbation 3: Single circle move with Rattler Teleport + circle_idx = _select_circle_context_aware(n, current_radii, current_centers) + + RATTLE_THRESHOLD = 0.025 + RELOCATE_PROB = 0.3 # Probability to teleport a rattler + + if current_radii[circle_idx] < RATTLE_THRESHOLD and np.random.rand() < RELOCATE_PROB: + candidate_centers[circle_idx] = np.random.uniform(0.05, 0.95, 2) + else: + # Standard displacement + effective_perturb_strength = _adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay boosts + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + return best_centers + +def initialization_stage(n): + """Performs a multi-start initialization and selects the best starting point.""" + best_initial_sum_radii = -1.0 + best_initial_centers = None + + # Diverse void configurations to try + void_configs = [ + (np.array([0.4, 0.2]), 0.06), + (np.array([0.2, 0.4]), 0.05), + (np.array([0.6, 0.8]), 0.07), + (np.array([0.8, 0.6]), 0.065), + (np.array([0.5, 0.5]), 0.05), + (np.random.uniform(0.3, 0.7, 2), 0.08), + ] + + for void_center, amplitude in void_configs: + candidate_centers = _generate_void_config(n, void_center, amplitude, sigma=0.15) + + # Settle with a very quick relaxation + relaxed_centers = relaxation_stage( + candidate_centers, iters=150, step_size=0.002, + repulsion_strength=0.02, boundary_strength=0.07, + repulsion_threshold=0.2, boundary_margin=0.04 + ) + candidate_radii = compute_max_radii(relaxed_centers) + candidate_sum_radii = np.sum(candidate_radii) + + if candidate_sum_radii > best_initial_sum_radii: + best_initial_sum_radii = candidate_sum_radii + best_initial_centers = relaxed_centers.copy() + + return best_initial_centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a functional, + multi-stage optimization pipeline. + """ + n = 26 + + # Stage 1: Multi-Start Initialization to find a robust starting point + initial_centers = initialization_stage(n) + + # Stage 2: Main Simulated Annealing optimization + # The initial relaxation is now part of the initialization stage, + # so we can directly proceed to annealing. + annealed_centers = annealing_stage(initial_centers, n) + + # Stage 3: Final gentle polish using relaxation + final_centers = relaxation_stage( + annealed_centers, iters=300, step_size=0.0001, + repulsion_strength=0.001, boundary_strength=0.005, + repulsion_threshold=0.18, boundary_margin=0.02 + ) + + # Final evaluation + final_radii = compute_max_radii(final_centers) + annealed_radii = compute_max_radii(annealed_centers) + + # Return the best result between the SA output and the polished version + if np.sum(final_radii) > np.sum(annealed_radii): + return final_centers, final_radii + else: + return annealed_centers, annealed_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/original.py new file mode 100644 index 0000000000000000000000000000000000000000..cb3006a9309ff7c5b4d2c0702339774fcca34bc6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/original.py @@ -0,0 +1,275 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(500): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + return radii + +def _generate_void_config(n, void_center, amplitude, sigma): + """Helper to generate initial centers from a grid deformed by a Gaussian push.""" + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] + + initial_centers = np.zeros((n, 2)) + initial_centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + initial_centers[25] = void_center + return np.clip(initial_centers, 0.0, 1.0) + +def relaxation_stage(centers, iters, step_size, repulsion_strength, boundary_strength, repulsion_threshold, boundary_margin): + """Performs a vectorized force-directed relaxation (jiggle) phase.""" + relaxed_centers = centers.copy() + for _ in range(iters): + diff = relaxed_centers[:, np.newaxis, :] - relaxed_centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, relaxed_centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - relaxed_centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, relaxed_centers[:, 1] - (1 - boundary_margin)) + + relaxed_centers += step_size * forces + relaxed_centers = np.clip(relaxed_centers, 0.0, 1.0) + return relaxed_centers + +def _select_circle_context_aware(n, current_radii, current_centers): + """Intelligently selects a circle to perturb based on radius, boundary proximity, and crowding.""" + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_weight = np.exp(-dist_to_boundary / 0.08) + + neighbor_counts = np.zeros(n) + for i in range(n): + dists = np.linalg.norm(current_centers[i] - current_centers, axis=1) + crowd_dist = (current_radii[i] + current_radii) * 1.1 + neighbor_counts[i] = np.sum(dists < crowd_dist) - 1 + + max_neighbors = np.max(neighbor_counts) + crowding_weight = (neighbor_counts / (max_neighbors + 1e-8)) if max_neighbors > 0 else np.zeros(n) + + combined_weights = inverse_radii * (1 + boundary_weight) * (1 + crowding_weight) + selection_probs = combined_weights / np.sum(combined_weights) + return np.random.choice(n, p=selection_probs) + +def _adaptive_perturbation_strength(base_strength, circle_idx, current_radii): + """Calculates a larger perturbation for smaller circles.""" + max_r = np.max(current_radii) + 1e-8 + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 1.5 + return base_strength * perturb_factor + +def annealing_stage(centers, n): + """Performs the main simulated annealing optimization stage.""" + current_centers = centers.copy() + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_sum_radii = current_sum_radii + + # SA Parameters + total_iterations = 20000 + initial_temp = 0.0008 + final_temp = 1e-9 + initial_perturb_strength = 0.035 + final_perturb_strength = 0.0001 + + # Stagnation Escape Parameters + stagnation_counter = 0 + stagnation_threshold = 800 + perturb_boost = 1.0 + boost_factor = 3.0 + boost_decay = 0.98 + + # New parameters for swap perturbation, integrated with stagnation escape + base_swap_prob = 0.1 + swap_prob_boost = 1.0 + swap_prob_boost_factor = 3.0 # Temporarily triple the swap probability + swap_prob_boost_decay = 0.98 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + + # Annealing schedules + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Stagnation escape: boost perturbation, swap prob, and reheat temperature + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + swap_prob_boost = swap_prob_boost_factor + temp = temp_schedule + initial_temp * 0.4 # Reheat + stagnation_counter = 0 + else: + temp = temp_schedule + + candidate_centers = current_centers.copy() + + current_swap_prob = np.clip(base_swap_prob * swap_prob_boost, 0, 0.5) + + if np.random.rand() < current_swap_prob: + # Swap Perturbation: swap a small circle with a large one + sorted_indices = np.argsort(current_radii) + if n > 1: + num_small = n // 2 + small_circles_indices = sorted_indices[:num_small] + large_circles_indices = sorted_indices[num_small:] + + if len(small_circles_indices) > 0 and len(large_circles_indices) > 0: + idx_small = np.random.choice(small_circles_indices) + idx_large = np.random.choice(large_circles_indices) + + # Swap positions + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() + else: + # Standard Displacement Perturbation + circle_idx = _select_circle_context_aware(n, current_radii, current_centers) + effective_perturb_strength = _adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay boosts + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + if swap_prob_boost > 1.0: + swap_prob_boost = 1.0 + (swap_prob_boost - 1.0) * swap_prob_boost_decay + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + return best_centers + +def initialization_stage(n): + """Performs a multi-start initialization and selects the best starting point.""" + best_initial_sum_radii = -1.0 + best_initial_centers = None + + # Diverse void configurations to try + void_configs = [ + (np.array([0.4, 0.2]), 0.06), + (np.array([0.2, 0.4]), 0.05), + (np.array([0.6, 0.8]), 0.07), + (np.array([0.8, 0.6]), 0.065), + (np.array([0.5, 0.5]), 0.05), + (np.random.uniform(0.3, 0.7, 2), 0.08), + ] + + for void_center, amplitude in void_configs: + candidate_centers = _generate_void_config(n, void_center, amplitude, sigma=0.15) + + # Settle with a very quick relaxation + relaxed_centers = relaxation_stage( + candidate_centers, iters=150, step_size=0.002, + repulsion_strength=0.02, boundary_strength=0.07, + repulsion_threshold=0.2, boundary_margin=0.04 + ) + candidate_radii = compute_max_radii(relaxed_centers) + candidate_sum_radii = np.sum(candidate_radii) + + if candidate_sum_radii > best_initial_sum_radii: + best_initial_sum_radii = candidate_sum_radii + best_initial_centers = relaxed_centers.copy() + + return best_initial_centers + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a functional, + multi-stage optimization pipeline. + """ + n = 26 + + # Stage 1: Multi-Start Initialization to find a robust starting point + initial_centers = initialization_stage(n) + + # Stage 2: Main Simulated Annealing optimization + # The initial relaxation is now part of the initialization stage, + # so we can directly proceed to annealing. + annealed_centers = annealing_stage(initial_centers, n) + + # Stage 3: Final gentle polish using relaxation + final_centers = relaxation_stage( + annealed_centers, iters=300, step_size=0.0001, + repulsion_strength=0.001, boundary_strength=0.005, + repulsion_threshold=0.18, boundary_margin=0.02 + ) + + # Final evaluation + final_radii = compute_max_radii(final_centers) + annealed_radii = compute_max_radii(annealed_centers) + + # Return the best result between the SA output and the polished version + if np.sum(final_radii) > np.sum(annealed_radii): + return final_centers, final_radii + else: + return annealed_centers, annealed_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..4484402b729ea91b252853d1d10fda1565d95fc4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_195/main.py:65: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..5f80748f93af0a07b71c4eb185a452094a2a9916 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_195/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_195/results +Run 1/1 completed in 94.41 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.412494259262323 + public: {'centers_str': ' centers[0] = (0.0869, 0.0869)\n centers[1] = (0.4129, 0.2122)\n centers[2] = (0.7468, 0.7543)\n centers[3] = (0.4152, 0.6330)\n centers[4] = (0.1207, 0.2932)\n centers[5] = (0.8650, 0.1452)\n centers[6] = (0.7100, 0.2850)\n centers[7] = (0.4849, 0.3435)\n centers[8] = (0.9150, 0.3076)\n centers[9] = (0.2567, 0.4922)\n centers[10] = (0.1029, 0.6615)\n centers[11] = (0.7237, 0.0737)\n centers[12] = (0.0996, 0.8979)\n centers[13] = (0.5364, 0.1190)\n centers[14] = (0.9030, 0.4893)\n centers[15] = (0.6673, 0.5488)\n centers[16] = (0.2998, 0.7010)\n centers[17] = (0.4899, 0.7082)\n centers[18] = (0.4384, 0.5406)\n centers[19] = (0.8937, 0.6925)\n centers[20] = (0.7000, 0.9000)\n centers[21] = (0.2998, 0.8994)\n centers[22] = (0.5002, 0.9002)\n centers[23] = (0.9000, 0.8994)\n centers[24] = (0.2940, 0.1235)\n centers[25] = (0.0760, 0.4839)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.412494259262323} + visualization_path: + execution_time_mean: 94.41124824620783 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..508bdc8a63c0fbd6acde885c4c47bcdfdc7738ce --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.412494259262323, + "public": { + "centers_str": " centers[0] = (0.0869, 0.0869)\n centers[1] = (0.4129, 0.2122)\n centers[2] = (0.7468, 0.7543)\n centers[3] = (0.4152, 0.6330)\n centers[4] = (0.1207, 0.2932)\n centers[5] = (0.8650, 0.1452)\n centers[6] = (0.7100, 0.2850)\n centers[7] = (0.4849, 0.3435)\n centers[8] = (0.9150, 0.3076)\n centers[9] = (0.2567, 0.4922)\n centers[10] = (0.1029, 0.6615)\n centers[11] = (0.7237, 0.0737)\n centers[12] = (0.0996, 0.8979)\n centers[13] = (0.5364, 0.1190)\n centers[14] = (0.9030, 0.4893)\n centers[15] = (0.6673, 0.5488)\n centers[16] = (0.2998, 0.7010)\n centers[17] = (0.4899, 0.7082)\n centers[18] = (0.4384, 0.5406)\n centers[19] = (0.8937, 0.6925)\n centers[20] = (0.7000, 0.9000)\n centers[21] = (0.2998, 0.8994)\n centers[22] = (0.5002, 0.9002)\n centers[23] = (0.9000, 0.8994)\n centers[24] = (0.2940, 0.1235)\n centers[25] = (0.0760, 0.4839)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.412494259262323 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_195/results/packing_viz.png", + "execution_time_mean": 94.41124824620783, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..63c180b65f50956d3f8f8ad768393440ac280043 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_195/search_replace.txt @@ -0,0 +1,238 @@ +Hello! As a mathematician specializing in computational geometry, I've analyzed the provided visualization and the code. Here's my assessment and proposed improvement. + +**Analysis of the Visualization** + +* **Spatial Distribution:** The circles are not optimally distributed. There's a mix of structured rows (top) and disordered sections (center/bottom). +* **Unused Space:** I've spotted at least two significant areas of inefficiency. First, a tiny, almost invisible "rattler" circle is trapped near `(x=0.6, y=0.55)`, contributing virtually nothing to the score and blocking its neighbors from expanding. Second, there's a noticeable gap in the left-middle area around `(x=0.2, y=0.55)` that could accommodate a larger circle. +* **Edge Utilization:** The top and left edges are used relatively well, but the bottom and right edges show gaps and could support larger circles, especially in the corners. +* **Inefficient Patterns:** The two large yellow circles in the bottom half create awkward boundaries, leading to a disorganized packing of smaller circles around them. The overall structure lacks the crystalline, hexagonal-like motifs often seen in optimal packings. + +My proposed change aims to directly address these issues, particularly the "rattler" problem and the tendency to get stuck in disordered local minima. + + +multi_modal_perturbation_and_longer_anneal + + + +Based on the visual analysis, the current packing has "rattler" circles (tiny, useless circles trapped by larger ones) and some disordered regions. The current simulated annealing only uses two perturbation types (swap and single displacement), which can struggle to escape these local minima. + +This edit introduces a more diverse set of perturbation moves to improve exploration: +1. **Cluster Move**: A new perturbation type is added that selects a small circle and its two nearest neighbors and moves them as a group. This helps rearrange locally stuck configurations. +2. **Rattler Teleport**: The standard single-circle move is enhanced. If a very small circle (a "rattler") is selected, it has a chance to be "teleported" to a completely new random location instead of just being nudged. This is highly effective at freeing up space blocked by uselessly small circles. +3. **Longer Annealing Schedule**: The total number of annealing iterations is increased from 20,000 to 35,000 to give these new, more complex moves sufficient time to find better solutions. +4. **Refined SA Parameters**: The stagnation logic is simplified to use a single perturbation boost, and other parameters (`initial_temp`, `stagnation_threshold`, etc.) are tuned to better suit the longer search and new move set. The swap move now picks from the extreme quartiles for more impactful swaps. + +These changes create a more robust search algorithm capable of escaping a wider variety of local optima, directly addressing the inefficiencies observed in the visualization. + + + +<<<<<<< SEARCH +def annealing_stage(centers, n): + """Performs the main simulated annealing optimization stage.""" + current_centers = centers.copy() + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_sum_radii = current_sum_radii + + # SA Parameters + total_iterations = 20000 + initial_temp = 0.0008 + final_temp = 1e-9 + initial_perturb_strength = 0.035 + final_perturb_strength = 0.0001 + + # Stagnation Escape Parameters + stagnation_counter = 0 + stagnation_threshold = 800 + perturb_boost = 1.0 + boost_factor = 3.0 + boost_decay = 0.98 + + # New parameters for swap perturbation, integrated with stagnation escape + base_swap_prob = 0.1 + swap_prob_boost = 1.0 + swap_prob_boost_factor = 3.0 # Temporarily triple the swap probability + swap_prob_boost_decay = 0.98 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + + # Annealing schedules + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Stagnation escape: boost perturbation, swap prob, and reheat temperature + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + swap_prob_boost = swap_prob_boost_factor + temp = temp_schedule + initial_temp * 0.4 # Reheat + stagnation_counter = 0 + else: + temp = temp_schedule + + candidate_centers = current_centers.copy() + + current_swap_prob = np.clip(base_swap_prob * swap_prob_boost, 0, 0.5) + + if np.random.rand() < current_swap_prob: + # Swap Perturbation: swap a small circle with a large one + sorted_indices = np.argsort(current_radii) + if n > 1: + num_small = n // 2 + small_circles_indices = sorted_indices[:num_small] + large_circles_indices = sorted_indices[num_small:] + + if len(small_circles_indices) > 0 and len(large_circles_indices) > 0: + idx_small = np.random.choice(small_circles_indices) + idx_large = np.random.choice(large_circles_indices) + + # Swap positions + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() + else: + # Standard Displacement Perturbation + circle_idx = _select_circle_context_aware(n, current_radii, current_centers) + effective_perturb_strength = _adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay boosts + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + if swap_prob_boost > 1.0: + swap_prob_boost = 1.0 + (swap_prob_boost - 1.0) * swap_prob_boost_decay + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + return best_centers +======= +def annealing_stage(centers, n): + """Performs the main simulated annealing optimization stage.""" + current_centers = centers.copy() + current_radii = compute_max_radii(current_centers) + current_sum_radii = np.sum(current_radii) + + best_centers = current_centers.copy() + best_sum_radii = current_sum_radii + + # SA Parameters + total_iterations = 35000 + initial_temp = 0.001 + final_temp = 1e-10 + initial_perturb_strength = 0.04 + final_perturb_strength = 0.0001 + + # Stagnation Escape Parameters + stagnation_counter = 0 + stagnation_threshold = 1500 + perturb_boost = 1.0 + boost_factor = 4.0 + boost_decay = 0.97 + temp_reheat_factor = 0.5 + + # Perturbation move probabilities + swap_prob = 0.10 + cluster_prob = 0.15 + + for iteration in range(total_iterations): + progress = iteration / total_iterations + + # Annealing schedules + temp_schedule = initial_temp * math.exp(math.log(final_temp / initial_temp) * progress) + base_perturb_strength = initial_perturb_strength * math.exp(math.log(final_perturb_strength / initial_perturb_strength) * progress) + + # Stagnation escape: boost perturbation and reheat temperature + if stagnation_counter >= stagnation_threshold: + perturb_boost = boost_factor + temp = temp_schedule + initial_temp * temp_reheat_factor # Reheat + stagnation_counter = 0 + else: + temp = temp_schedule + + candidate_centers = current_centers.copy() + rand_val = np.random.rand() + + if rand_val < swap_prob: + # Perturbation 1: Swap small and large circles + sorted_indices = np.argsort(current_radii) + if n > 1: + num_candidates = max(1, n // 4) + idx_small = np.random.choice(sorted_indices[:num_candidates]) + idx_large = np.random.choice(sorted_indices[-num_candidates:]) + if idx_small != idx_large: + candidate_centers[idx_small], candidate_centers[idx_large] = \ + candidate_centers[idx_large].copy(), candidate_centers[idx_small].copy() + + elif rand_val < swap_prob + cluster_prob: + # Perturbation 2: Cluster move + primary_idx = _select_circle_context_aware(n, current_radii, current_centers) + distances = np.linalg.norm(current_centers - current_centers[primary_idx], axis=1) + distances[primary_idx] = np.inf + neighbor_indices = np.argsort(distances)[:2] + indices_to_perturb = np.append(neighbor_indices, primary_idx) + + eff_strength = _adaptive_perturbation_strength(base_perturb_strength, primary_idx, current_radii) * perturb_boost * 0.6 + displacement = np.random.uniform(-eff_strength, eff_strength, 2) + candidate_centers[indices_to_perturb] += displacement + candidate_centers[indices_to_perturb] = np.clip(candidate_centers[indices_to_perturb], 0.0, 1.0) + + else: + # Perturbation 3: Single circle move with Rattler Teleport + circle_idx = _select_circle_context_aware(n, current_radii, current_centers) + + RATTLE_THRESHOLD = 0.025 + RELOCATE_PROB = 0.3 # Probability to teleport a rattler + + if current_radii[circle_idx] < RATTLE_THRESHOLD and np.random.rand() < RELOCATE_PROB: + candidate_centers[circle_idx] = np.random.uniform(0.05, 0.95, 2) + else: + # Standard displacement + effective_perturb_strength = _adaptive_perturbation_strength(base_perturb_strength, circle_idx, current_radii) * perturb_boost + displacement = np.random.uniform(-effective_perturb_strength, effective_perturb_strength, 2) + candidate_centers[circle_idx] += displacement + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx], 0.0, 1.0) + + # Decay boosts + if perturb_boost > 1.0: + perturb_boost = 1.0 + (perturb_boost - 1.0) * boost_decay + + candidate_radii = compute_max_radii(candidate_centers) + candidate_sum_radii = np.sum(candidate_radii) + + delta_E = candidate_sum_radii - current_sum_radii + if delta_E > 0 or (temp > 1e-10 and np.random.rand() < math.exp(delta_E / temp)): + current_centers = candidate_centers + current_radii = candidate_radii + current_sum_radii = candidate_sum_radii + + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + stagnation_counter = 0 + else: + stagnation_counter += 1 + else: + stagnation_counter += 1 + + return best_centers +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9269c7cf75452477e06cb37c47e920fc9f949c3a Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..e8ff753ef9b56a24b7a599e1f2c37a721bfd5735 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/edit.diff @@ -0,0 +1,329 @@ +--- a/original.py ++++ b/original.py +@@ -1,306 +1,313 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math # Needed for math.exp + + # Utility functions (kept outside classes as they are general calculations) + def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): # Use the passed max_iterations parameter + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + + def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + Combines features from high-performing ancestors. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void (from Program 2 / high-performing ancestor). + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) # From high-performing ancestor + amplitude = 0.06 # From high-performing ancestor + sigma = 0.15 # From high-performing ancestor + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding (combining Program 1 and 2 heuristics). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric (from Program 1) - helps prioritize circles in dense regions + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 # Distance threshold to consider another circle 'crowding' + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 # Maximum possible neighbors + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 # How much crowding influences selection (tuneable) + + # Combine all weights: inverse radii * boundary proximity * crowding + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation (from Program 2). + """ + max_r = np.max(current_radii) + 1e-8 # Avoid division by zero + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 # More aggressive movement for smaller circles + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing with advanced heuristics. + """ + self._initialize_centers() + + # Pre-optimization with F-D relaxation using aggressive parameters from the best previous result (2.39 score) + self.centers = apply_force_directed_relaxation( + self.centers.copy(), + iterations=800, # Increased iterations for more thorough settling + step_size=0.0015, # Increased step size for more movement + repulsion_strength=0.015, # Increased repulsion strength + repulsion_threshold=0.22, # Increased threshold for broader initial spread + boundary_strength=0.08, # Increased boundary repulsion + boundary_margin=0.03 # Maintained + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + # Initialize current and best states for Simulated Annealing + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + # SA parameters + total_iterations = 20000 # Increased total iterations for more exploration + initial_global_perturb_strength_base = 0.05 # Slightly higher initial perturb for broader search + final_global_perturb_strength = 0.0002 # Slightly lower final perturb for finer tuning + T_initial = 0.25 # Increased initial temperature for broader initial acceptance + T_final = 1e-8 # Lower final temperature for very greedy behavior at the end + + # Stagnation escape mechanism parameters + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_perturb = initial_global_perturb_strength_base + stagnation_boost_active_counter = 0 + stagnation_boost_duration = 200 + stagnation_aggressive_perturb_multiplier = 2.0 + +- # Cluster perturbation probability (Recommendation 2) +- cluster_perturb_prob = 0.20 # Increased chance for multi-circle moves ++ # Multi-modal perturbation probabilities ++ swap_prob = 0.05 # Probability of swapping two circles ++ cluster_perturb_prob = 0.15 # Chance for multi-circle moves (adjusted for swap) + + for iteration in range(total_iterations): + # Annealing schedules + global_perturb_strength = current_initial_perturb * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape + if stagnation_boost_active_counter > 0: + global_perturb_strength *= stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + # Temperature decays exponentially + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (Recommendation 3) + # Starts with fewer iterations, increases precision as temperature drops + min_radii_iter = 100 + max_radii_iter = 750 + # Linearly increase iterations as temperature drops + current_radii_iterations = int(max_radii_iter - (max_radii_iter - min_radii_iter) * (temperature / T_initial)) + if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration + +- # Multi-modal perturbation choice: cluster or single circle +- if np.random.rand() < cluster_perturb_prob: +- primary_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster +- +- # Find closest neighbors to form a cluster ++ # Multi-modal perturbation: swap, cluster, or single move ++ move_type_rand = np.random.rand() ++ if move_type_rand < swap_prob: ++ # Swap Perturbation: Swaps the positions of two randomly chosen circles. ++ # This is a large-scale move intended to break out of deep local optima. ++ if self.n > 1: ++ i, j = np.random.choice(self.n, 2, replace=False) ++ candidate_centers[i], candidate_centers[j] = candidate_centers[j].copy(), candidate_centers[i].copy() ++ ++ elif move_type_rand < swap_prob + cluster_perturb_prob: ++ # Cluster Perturbation: Moves a small group of circles together. ++ primary_idx = np.random.choice(self.n) ++ + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [primary_idx] +- num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors ++ num_neighbors_to_include = np.random.choice([1, 2]) + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + +- # Apply a coordinated, smaller displacement to the entire cluster + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) +- cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move +- +- # Generate a single random direction for the entire cluster ++ cluster_displacement_magnitude = 0.5 * eff_perturb ++ + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) +- else: # Fallback to single circle if no neighbors for cluster (e.g., n=1) ++ else: # Fallback to single circle move + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case, using adaptive selection and strength) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluate candidate configuration using adaptive iterations for compute_max_radii + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + accepted = False + delta = candidate_sum_radii - current_sum_radii + # Accept better solutions or worse solutions with probability based on temperature + if delta > 0 or (temperature > 1e-10 and np.random.rand() < math.exp(delta / temperature)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best solution + elif not accepted: + no_improvement_count += 1 + # If stagnated for max_no_improvement_steps, activate escape mechanism + if no_improvement_count > max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential + stagnation_boost_active_counter = stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return best_centers, best_radii + + def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePacker and runs its packing method. + """ + packer = CirclePacker(n=26) + return packer.pack() + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/main.py new file mode 100644 index 0000000000000000000000000000000000000000..14b988397cd999efe671f143555c4d7222925517 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/main.py @@ -0,0 +1,313 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math # Needed for math.exp + +# Utility functions (kept outside classes as they are general calculations) +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): # Use the passed max_iterations parameter + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + Combines features from high-performing ancestors. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void (from Program 2 / high-performing ancestor). + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) # From high-performing ancestor + amplitude = 0.06 # From high-performing ancestor + sigma = 0.15 # From high-performing ancestor + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding (combining Program 1 and 2 heuristics). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric (from Program 1) - helps prioritize circles in dense regions + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 # Distance threshold to consider another circle 'crowding' + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 # Maximum possible neighbors + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 # How much crowding influences selection (tuneable) + + # Combine all weights: inverse radii * boundary proximity * crowding + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation (from Program 2). + """ + max_r = np.max(current_radii) + 1e-8 # Avoid division by zero + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 # More aggressive movement for smaller circles + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing with advanced heuristics. + """ + self._initialize_centers() + + # Pre-optimization with F-D relaxation using aggressive parameters from the best previous result (2.39 score) + self.centers = apply_force_directed_relaxation( + self.centers.copy(), + iterations=800, # Increased iterations for more thorough settling + step_size=0.0015, # Increased step size for more movement + repulsion_strength=0.015, # Increased repulsion strength + repulsion_threshold=0.22, # Increased threshold for broader initial spread + boundary_strength=0.08, # Increased boundary repulsion + boundary_margin=0.03 # Maintained + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + # Initialize current and best states for Simulated Annealing + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + # SA parameters + total_iterations = 20000 # Increased total iterations for more exploration + initial_global_perturb_strength_base = 0.05 # Slightly higher initial perturb for broader search + final_global_perturb_strength = 0.0002 # Slightly lower final perturb for finer tuning + T_initial = 0.25 # Increased initial temperature for broader initial acceptance + T_final = 1e-8 # Lower final temperature for very greedy behavior at the end + + # Stagnation escape mechanism parameters + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_perturb = initial_global_perturb_strength_base + stagnation_boost_active_counter = 0 + stagnation_boost_duration = 200 + stagnation_aggressive_perturb_multiplier = 2.0 + + # Multi-modal perturbation probabilities + swap_prob = 0.05 # Probability of swapping two circles + cluster_perturb_prob = 0.15 # Chance for multi-circle moves (adjusted for swap) + + for iteration in range(total_iterations): + # Annealing schedules + global_perturb_strength = current_initial_perturb * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape + if stagnation_boost_active_counter > 0: + global_perturb_strength *= stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + # Temperature decays exponentially + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (Recommendation 3) + # Starts with fewer iterations, increases precision as temperature drops + min_radii_iter = 100 + max_radii_iter = 750 + # Linearly increase iterations as temperature drops + current_radii_iterations = int(max_radii_iter - (max_radii_iter - min_radii_iter) * (temperature / T_initial)) + if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration + + # Multi-modal perturbation: swap, cluster, or single move + move_type_rand = np.random.rand() + if move_type_rand < swap_prob: + # Swap Perturbation: Swaps the positions of two randomly chosen circles. + # This is a large-scale move intended to break out of deep local optima. + if self.n > 1: + i, j = np.random.choice(self.n, 2, replace=False) + candidate_centers[i], candidate_centers[j] = candidate_centers[j].copy(), candidate_centers[i].copy() + + elif move_type_rand < swap_prob + cluster_perturb_prob: + # Cluster Perturbation: Moves a small group of circles together. + primary_idx = np.random.choice(self.n) + + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [primary_idx] + num_neighbors_to_include = np.random.choice([1, 2]) + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb + + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle move + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case, using adaptive selection and strength) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluate candidate configuration using adaptive iterations for compute_max_radii + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + accepted = False + delta = candidate_sum_radii - current_sum_radii + # Accept better solutions or worse solutions with probability based on temperature + if delta > 0 or (temperature > 1e-10 and np.random.rand() < math.exp(delta / temperature)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best solution + elif not accepted: + no_improvement_count += 1 + # If stagnated for max_no_improvement_steps, activate escape mechanism + if no_improvement_count > max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential + stagnation_boost_active_counter = stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePacker and runs its packing method. + """ + packer = CirclePacker(n=26) + return packer.pack() +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/original.py new file mode 100644 index 0000000000000000000000000000000000000000..92789c1bce9d818685ea7cd0b162a648f843b5ca --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/original.py @@ -0,0 +1,306 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math # Needed for math.exp + +# Utility functions (kept outside classes as they are general calculations) +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): # Use the passed max_iterations parameter + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + Combines features from high-performing ancestors. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void (from Program 2 / high-performing ancestor). + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) # From high-performing ancestor + amplitude = 0.06 # From high-performing ancestor + sigma = 0.15 # From high-performing ancestor + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding (combining Program 1 and 2 heuristics). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric (from Program 1) - helps prioritize circles in dense regions + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 # Distance threshold to consider another circle 'crowding' + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 # Maximum possible neighbors + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 # How much crowding influences selection (tuneable) + + # Combine all weights: inverse radii * boundary proximity * crowding + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation (from Program 2). + """ + max_r = np.max(current_radii) + 1e-8 # Avoid division by zero + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 # More aggressive movement for smaller circles + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing with advanced heuristics. + """ + self._initialize_centers() + + # Pre-optimization with F-D relaxation using aggressive parameters from the best previous result (2.39 score) + self.centers = apply_force_directed_relaxation( + self.centers.copy(), + iterations=800, # Increased iterations for more thorough settling + step_size=0.0015, # Increased step size for more movement + repulsion_strength=0.015, # Increased repulsion strength + repulsion_threshold=0.22, # Increased threshold for broader initial spread + boundary_strength=0.08, # Increased boundary repulsion + boundary_margin=0.03 # Maintained + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + # Initialize current and best states for Simulated Annealing + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + # SA parameters + total_iterations = 20000 # Increased total iterations for more exploration + initial_global_perturb_strength_base = 0.05 # Slightly higher initial perturb for broader search + final_global_perturb_strength = 0.0002 # Slightly lower final perturb for finer tuning + T_initial = 0.25 # Increased initial temperature for broader initial acceptance + T_final = 1e-8 # Lower final temperature for very greedy behavior at the end + + # Stagnation escape mechanism parameters + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_perturb = initial_global_perturb_strength_base + stagnation_boost_active_counter = 0 + stagnation_boost_duration = 200 + stagnation_aggressive_perturb_multiplier = 2.0 + + # Cluster perturbation probability (Recommendation 2) + cluster_perturb_prob = 0.20 # Increased chance for multi-circle moves + + for iteration in range(total_iterations): + # Annealing schedules + global_perturb_strength = current_initial_perturb * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape + if stagnation_boost_active_counter > 0: + global_perturb_strength *= stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + # Temperature decays exponentially + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (Recommendation 3) + # Starts with fewer iterations, increases precision as temperature drops + min_radii_iter = 100 + max_radii_iter = 750 + # Linearly increase iterations as temperature drops + current_radii_iterations = int(max_radii_iter - (max_radii_iter - min_radii_iter) * (temperature / T_initial)) + if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration + + # Multi-modal perturbation choice: cluster or single circle + if np.random.rand() < cluster_perturb_prob: + primary_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster + + # Find closest neighbors to form a cluster + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [primary_idx] + num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + # Apply a coordinated, smaller displacement to the entire cluster + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move + + # Generate a single random direction for the entire cluster + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle if no neighbors for cluster (e.g., n=1) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case, using adaptive selection and strength) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluate candidate configuration using adaptive iterations for compute_max_radii + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + accepted = False + delta = candidate_sum_radii - current_sum_radii + # Accept better solutions or worse solutions with probability based on temperature + if delta > 0 or (temperature > 1e-10 and np.random.rand() < math.exp(delta / temperature)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best solution + elif not accepted: + no_improvement_count += 1 + # If stagnated for max_no_improvement_steps, activate escape mechanism + if no_improvement_count > max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential + stagnation_boost_active_counter = stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePacker and runs its packing method. + """ + packer = CirclePacker(n=26) + return packer.pack() +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..0d0c370788811ec78c1fdc52bf513965fb1df5f4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_196/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_196/results +Run 1/1 completed in 52.40 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.3274269101392475 + public: {'centers_str': ' centers[0] = (0.2315, 0.4397)\n centers[1] = (0.2431, 0.8829)\n centers[2] = (0.5557, 0.2600)\n centers[3] = (0.7841, 0.3738)\n centers[4] = (0.7783, 0.5812)\n centers[5] = (0.0621, 0.1428)\n centers[6] = (0.6839, 0.8406)\n centers[7] = (0.0606, 0.2670)\n centers[8] = (0.0786, 0.7130)\n centers[9] = (0.4779, 0.5731)\n centers[10] = (0.9212, 0.4501)\n centers[11] = (0.9466, 0.5941)\n centers[12] = (0.2495, 0.7389)\n centers[13] = (0.0980, 0.9028)\n centers[14] = (0.4129, 0.8792)\n centers[15] = (0.8381, 0.9582)\n centers[16] = (0.1710, 0.5640)\n centers[17] = (0.6750, 0.0876)\n centers[18] = (0.0824, 0.4090)\n centers[19] = (0.4258, 0.0911)\n centers[20] = (0.9319, 0.9000)\n centers[21] = (0.1497, 0.0594)\n centers[22] = (0.2677, 0.2747)\n centers[23] = (0.2729, 0.0642)\n centers[24] = (0.8702, 0.1838)\n centers[25] = (0.9083, 0.7419)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.3274269101392475} + visualization_path: + execution_time_mean: 52.39623380219564 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..acad5dfd1d104a375a2e7491c68f306a904e1d59 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.3274269101392475, + "public": { + "centers_str": " centers[0] = (0.2315, 0.4397)\n centers[1] = (0.2431, 0.8829)\n centers[2] = (0.5557, 0.2600)\n centers[3] = (0.7841, 0.3738)\n centers[4] = (0.7783, 0.5812)\n centers[5] = (0.0621, 0.1428)\n centers[6] = (0.6839, 0.8406)\n centers[7] = (0.0606, 0.2670)\n centers[8] = (0.0786, 0.7130)\n centers[9] = (0.4779, 0.5731)\n centers[10] = (0.9212, 0.4501)\n centers[11] = (0.9466, 0.5941)\n centers[12] = (0.2495, 0.7389)\n centers[13] = (0.0980, 0.9028)\n centers[14] = (0.4129, 0.8792)\n centers[15] = (0.8381, 0.9582)\n centers[16] = (0.1710, 0.5640)\n centers[17] = (0.6750, 0.0876)\n centers[18] = (0.0824, 0.4090)\n centers[19] = (0.4258, 0.0911)\n centers[20] = (0.9319, 0.9000)\n centers[21] = (0.1497, 0.0594)\n centers[22] = (0.2677, 0.2747)\n centers[23] = (0.2729, 0.0642)\n centers[24] = (0.8702, 0.1838)\n centers[25] = (0.9083, 0.7419)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.3274269101392475 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_196/results/packing_viz.png", + "execution_time_mean": 52.39623380219564, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..c86b6b4336b21ea75f67c72393bcaa352cc70ce1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_196/search_replace.txt @@ -0,0 +1,126 @@ +Based on my analysis of the visualization and the algorithm's structure, I propose introducing a "swap" perturbation move. This is a powerful technique for escaping deep local optima, which the current arrangement appears to be stuck in. + +### Visual Analysis & Rationale + +1. **Inefficient Patterns:** The visualization shows several instances where small circles (blue) are "trapped" between larger ones, preventing them from expanding. A key example is the small circle near coordinates (0.35, 0.1) lodged between two large yellow circles. This significantly limits the potential radii of the larger circles. Similarly, other small circles are positioned in ways that create unnecessary gaps. + +2. **Unused Space:** There are noticeable voids in the packing, such as the area above the large yellow circle near (0.7, 0.4) and between circles in the upper-left quadrant. These suggest that the current perturbation strategies (single-circle jiggle and small cluster moves) are not sufficient to perform the large-scale reorganization needed to fill these gaps. + +3. **Proposed Solution: Swap Perturbation:** A swap move directly addresses these issues by exchanging the positions of two circles. This allows a small, "blocking" circle to be moved to a less critical location, and a larger circle to be moved into a region where it has more room to grow. This constitutes a large jump in the search space, providing an excellent mechanism to break free from suboptimal configurations that local moves cannot escape. + +I will introduce this swap move with a 5% probability, adjusting the existing cluster move probability to maintain a balance of exploration strategies. + + +add_swap_perturbation + + +I am introducing a "swap" perturbation move. This move selects two random circles and swaps their center coordinates. This is a powerful, large-scale exploration strategy designed to break out of deep local optima, particularly those caused by small circles getting trapped between larger ones and preventing them from expanding—a pattern observed in the visualization. + +To implement this, I'm adding a `swap_prob` of 0.05. The main perturbation logic is now a three-way choice: +1. **Swap (5%):** Swaps two random circles. +2. **Cluster (15%):** Moves a small group of adjacent circles together. +3. **Single (80%):** The original move of perturbing one circle. + +This change diversifies the search process, enabling it to explore radically different configurations and improve the overall packing density. + + +<<<<<<< SEARCH + # Cluster perturbation probability (Recommendation 2) + cluster_perturb_prob = 0.20 # Increased chance for multi-circle moves + + for iteration in range(total_iterations): +======= + # Multi-modal perturbation probabilities + swap_prob = 0.05 # Probability of swapping two circles + cluster_perturb_prob = 0.15 # Chance for multi-circle moves (adjusted for swap) + + for iteration in range(total_iterations): +>>>>>>> REPLACE +<<<<<<< SEARCH + # Multi-modal perturbation choice: cluster or single circle + if np.random.rand() < cluster_perturb_prob: + primary_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster + + # Find closest neighbors to form a cluster + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [primary_idx] + num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + # Apply a coordinated, smaller displacement to the entire cluster + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move + + # Generate a single random direction for the entire cluster + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle if no neighbors for cluster (e.g., n=1) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case, using adaptive selection and strength) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) +======= + # Multi-modal perturbation: swap, cluster, or single move + move_type_rand = np.random.rand() + if move_type_rand < swap_prob: + # Swap Perturbation: Swaps the positions of two randomly chosen circles. + # This is a large-scale move intended to break out of deep local optima. + if self.n > 1: + i, j = np.random.choice(self.n, 2, replace=False) + candidate_centers[i], candidate_centers[j] = candidate_centers[j].copy(), candidate_centers[i].copy() + + elif move_type_rand < swap_prob + cluster_perturb_prob: + # Cluster Perturbation: Moves a small group of circles together. + primary_idx = np.random.choice(self.n) + + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [primary_idx] + num_neighbors_to_include = np.random.choice([1, 2]) + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb + + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle move + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case, using adaptive selection and strength) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..301f4e1549170e4ee0d3e80f6c7add0d673167fc Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..709e9d7c39f8a760fd05773b6fd2191d70bdb8ea --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/edit.diff @@ -0,0 +1,372 @@ +--- a/original.py ++++ b/original.py +@@ -1,306 +1,332 @@ + # EVOLVE-BLOCK-START + import numpy as np + import math # Needed for math.exp + + # Utility functions (kept outside classes as they are general calculations) + def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): # Use the passed max_iterations parameter + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + + def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + + class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + Combines features from high-performing ancestors. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void (from Program 2 / high-performing ancestor). + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) # From high-performing ancestor + amplitude = 0.06 # From high-performing ancestor + sigma = 0.15 # From high-performing ancestor + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding (combining Program 1 and 2 heuristics). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric (from Program 1) - helps prioritize circles in dense regions + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 # Distance threshold to consider another circle 'crowding' + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 # Maximum possible neighbors + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 # How much crowding influences selection (tuneable) + + # Combine all weights: inverse radii * boundary proximity * crowding + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation (from Program 2). + """ + max_r = np.max(current_radii) + 1e-8 # Avoid division by zero + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 # More aggressive movement for smaller circles + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing with advanced heuristics. + """ + self._initialize_centers() + + # Pre-optimization with F-D relaxation using aggressive parameters from the best previous result (2.39 score) + self.centers = apply_force_directed_relaxation( + self.centers.copy(), + iterations=800, # Increased iterations for more thorough settling + step_size=0.0015, # Increased step size for more movement + repulsion_strength=0.015, # Increased repulsion strength + repulsion_threshold=0.22, # Increased threshold for broader initial spread + boundary_strength=0.08, # Increased boundary repulsion + boundary_margin=0.03 # Maintained + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + # Initialize current and best states for Simulated Annealing + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + +- # SA parameters +- total_iterations = 20000 # Increased total iterations for more exploration +- initial_global_perturb_strength_base = 0.05 # Slightly higher initial perturb for broader search +- final_global_perturb_strength = 0.0002 # Slightly lower final perturb for finer tuning +- T_initial = 0.25 # Increased initial temperature for broader initial acceptance ++ # SA parameters, tuned for new swap perturbation ++ total_iterations = 25000 # More iterations to settle after big swaps ++ initial_global_perturb_strength_base = 0.05 # Maintained initial perturb for broader search ++ final_global_perturb_strength = 0.0001 # Finer tuning at the end ++ T_initial = 0.3 # Higher temperature to accept disruptive swaps + T_final = 1e-8 # Lower final temperature for very greedy behavior at the end + + # Stagnation escape mechanism parameters + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_perturb = initial_global_perturb_strength_base + stagnation_boost_active_counter = 0 + stagnation_boost_duration = 200 + stagnation_aggressive_perturb_multiplier = 2.0 + +- # Cluster perturbation probability (Recommendation 2) +- cluster_perturb_prob = 0.20 # Increased chance for multi-circle moves ++ # Perturbation probabilities for multi-modal search ++ swap_prob = 0.05 ++ cluster_perturb_prob = 0.20 + + for iteration in range(total_iterations): + # Annealing schedules + global_perturb_strength = current_initial_perturb * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape + if stagnation_boost_active_counter > 0: + global_perturb_strength *= stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + # Temperature decays exponentially + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (Recommendation 3) + # Starts with fewer iterations, increases precision as temperature drops + min_radii_iter = 100 + max_radii_iter = 750 + # Linearly increase iterations as temperature drops + current_radii_iterations = int(max_radii_iter - (max_radii_iter - min_radii_iter) * (temperature / T_initial)) + if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration + +- # Multi-modal perturbation choice: cluster or single circle +- if np.random.rand() < cluster_perturb_prob: +- primary_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster +- +- # Find closest neighbors to form a cluster +- all_indices = np.arange(self.n) +- other_indices = np.delete(all_indices, primary_idx) +- +- if len(other_indices) > 0: +- distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) +- sorted_neighbor_indices = other_indices[np.argsort(distances)] +- +- cluster_indices = [primary_idx] +- num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors +- for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): +- cluster_indices.append(sorted_neighbor_indices[i]) +- +- # Apply a coordinated, smaller displacement to the entire cluster +- eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) +- cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move +- +- # Generate a single random direction for the entire cluster +- angle = np.random.uniform(0, 2 * np.pi) +- direction = np.array([math.cos(angle), math.sin(angle)]) +- cluster_displacement = cluster_displacement_magnitude * direction +- +- for c_idx in cluster_indices: +- candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) +- else: # Fallback to single circle if no neighbors for cluster (e.g., n=1) ++ # --- Multi-modal perturbation: Swap, Cluster, or Single --- ++ rand_val = np.random.rand() ++ ++ if rand_val < swap_prob: ++ # SWAP MOVE: Swap a small circle with a large one to escape local minima. ++ sorted_radii_indices = np.argsort(current_radii) ++ quartile_size = self.n // 4 ++ swap_successful = False ++ if quartile_size > 0: ++ small_circle_idx_pool = sorted_radii_indices[:quartile_size] ++ large_circle_idx_pool = sorted_radii_indices[-quartile_size:] ++ ++ idx1 = np.random.choice(small_circle_idx_pool) ++ idx2 = np.random.choice(large_circle_idx_pool) ++ ++ if idx1 != idx2: ++ # Swap the center positions ++ candidate_centers[[idx1, idx2]] = candidate_centers[[idx2, idx1]] ++ swap_successful = True ++ ++ if not swap_successful: ++ # Fallback to single perturbation if swap is not possible or fails + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + +- else: # Single circle perturbation (most common case, using adaptive selection and strength) ++ elif rand_val < swap_prob + cluster_perturb_prob: ++ # CLUSTER MOVE: Coordinated move of a few neighboring circles. ++ primary_idx = np.random.choice(self.n) ++ ++ all_indices = np.arange(self.n) ++ other_indices = np.delete(all_indices, primary_idx) ++ ++ if len(other_indices) > 0: ++ distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) ++ sorted_neighbor_indices = other_indices[np.argsort(distances)] ++ ++ cluster_indices = [primary_idx] ++ num_neighbors_to_include = np.random.choice([1, 2]) ++ for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): ++ cluster_indices.append(sorted_neighbor_indices[i]) ++ ++ eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) ++ cluster_displacement_magnitude = 0.5 * eff_perturb ++ ++ angle = np.random.uniform(0, 2 * np.pi) ++ direction = np.array([math.cos(angle), math.sin(angle)]) ++ cluster_displacement = cluster_displacement_magnitude * direction ++ ++ for c_idx in cluster_indices: ++ candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) ++ else: # Fallback to single circle move ++ circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) ++ eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) ++ displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) ++ candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) ++ ++ else: ++ # SINGLE CIRCLE MOVE: Default adaptive perturbation. + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluate candidate configuration using adaptive iterations for compute_max_radii + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + accepted = False + delta = candidate_sum_radii - current_sum_radii + # Accept better solutions or worse solutions with probability based on temperature + if delta > 0 or (temperature > 1e-10 and np.random.rand() < math.exp(delta / temperature)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best solution + elif not accepted: + no_improvement_count += 1 + # If stagnated for max_no_improvement_steps, activate escape mechanism + if no_improvement_count > max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential + stagnation_boost_active_counter = stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return best_centers, best_radii + + def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePacker and runs its packing method. + """ + packer = CirclePacker(n=26) + return packer.pack() + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/main.py new file mode 100644 index 0000000000000000000000000000000000000000..204f8a5bd0382b233d4000c0e6291420156022cd --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/main.py @@ -0,0 +1,332 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math # Needed for math.exp + +# Utility functions (kept outside classes as they are general calculations) +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): # Use the passed max_iterations parameter + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + Combines features from high-performing ancestors. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void (from Program 2 / high-performing ancestor). + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) # From high-performing ancestor + amplitude = 0.06 # From high-performing ancestor + sigma = 0.15 # From high-performing ancestor + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding (combining Program 1 and 2 heuristics). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric (from Program 1) - helps prioritize circles in dense regions + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 # Distance threshold to consider another circle 'crowding' + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 # Maximum possible neighbors + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 # How much crowding influences selection (tuneable) + + # Combine all weights: inverse radii * boundary proximity * crowding + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation (from Program 2). + """ + max_r = np.max(current_radii) + 1e-8 # Avoid division by zero + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 # More aggressive movement for smaller circles + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing with advanced heuristics. + """ + self._initialize_centers() + + # Pre-optimization with F-D relaxation using aggressive parameters from the best previous result (2.39 score) + self.centers = apply_force_directed_relaxation( + self.centers.copy(), + iterations=800, # Increased iterations for more thorough settling + step_size=0.0015, # Increased step size for more movement + repulsion_strength=0.015, # Increased repulsion strength + repulsion_threshold=0.22, # Increased threshold for broader initial spread + boundary_strength=0.08, # Increased boundary repulsion + boundary_margin=0.03 # Maintained + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + # Initialize current and best states for Simulated Annealing + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + # SA parameters, tuned for new swap perturbation + total_iterations = 25000 # More iterations to settle after big swaps + initial_global_perturb_strength_base = 0.05 # Maintained initial perturb for broader search + final_global_perturb_strength = 0.0001 # Finer tuning at the end + T_initial = 0.3 # Higher temperature to accept disruptive swaps + T_final = 1e-8 # Lower final temperature for very greedy behavior at the end + + # Stagnation escape mechanism parameters + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_perturb = initial_global_perturb_strength_base + stagnation_boost_active_counter = 0 + stagnation_boost_duration = 200 + stagnation_aggressive_perturb_multiplier = 2.0 + + # Perturbation probabilities for multi-modal search + swap_prob = 0.05 + cluster_perturb_prob = 0.20 + + for iteration in range(total_iterations): + # Annealing schedules + global_perturb_strength = current_initial_perturb * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape + if stagnation_boost_active_counter > 0: + global_perturb_strength *= stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + # Temperature decays exponentially + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (Recommendation 3) + # Starts with fewer iterations, increases precision as temperature drops + min_radii_iter = 100 + max_radii_iter = 750 + # Linearly increase iterations as temperature drops + current_radii_iterations = int(max_radii_iter - (max_radii_iter - min_radii_iter) * (temperature / T_initial)) + if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration + + # --- Multi-modal perturbation: Swap, Cluster, or Single --- + rand_val = np.random.rand() + + if rand_val < swap_prob: + # SWAP MOVE: Swap a small circle with a large one to escape local minima. + sorted_radii_indices = np.argsort(current_radii) + quartile_size = self.n // 4 + swap_successful = False + if quartile_size > 0: + small_circle_idx_pool = sorted_radii_indices[:quartile_size] + large_circle_idx_pool = sorted_radii_indices[-quartile_size:] + + idx1 = np.random.choice(small_circle_idx_pool) + idx2 = np.random.choice(large_circle_idx_pool) + + if idx1 != idx2: + # Swap the center positions + candidate_centers[[idx1, idx2]] = candidate_centers[[idx2, idx1]] + swap_successful = True + + if not swap_successful: + # Fallback to single perturbation if swap is not possible or fails + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + elif rand_val < swap_prob + cluster_perturb_prob: + # CLUSTER MOVE: Coordinated move of a few neighboring circles. + primary_idx = np.random.choice(self.n) + + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [primary_idx] + num_neighbors_to_include = np.random.choice([1, 2]) + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb + + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle move + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: + # SINGLE CIRCLE MOVE: Default adaptive perturbation. + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluate candidate configuration using adaptive iterations for compute_max_radii + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + accepted = False + delta = candidate_sum_radii - current_sum_radii + # Accept better solutions or worse solutions with probability based on temperature + if delta > 0 or (temperature > 1e-10 and np.random.rand() < math.exp(delta / temperature)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best solution + elif not accepted: + no_improvement_count += 1 + # If stagnated for max_no_improvement_steps, activate escape mechanism + if no_improvement_count > max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential + stagnation_boost_active_counter = stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePacker and runs its packing method. + """ + packer = CirclePacker(n=26) + return packer.pack() +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/original.py new file mode 100644 index 0000000000000000000000000000000000000000..92789c1bce9d818685ea7cd0b162a648f843b5ca --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/original.py @@ -0,0 +1,306 @@ +# EVOLVE-BLOCK-START +import numpy as np +import math # Needed for math.exp + +# Utility functions (kept outside classes as they are general calculations) +def compute_max_radii(centers, max_iterations=500): + """ + Compute the maximum possible radii for each circle position such that they + don't overlap and stay within the unit square. This is an iterative version + that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + max_iterations: int, maximum number of iterations to resolve overlaps. + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + for _ in range(max_iterations): # Use the passed max_iterations parameter + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + elif radii[i] > 0 or radii[j] > 0: + radii[i], radii[j] = 0, 0 + changes_made = True + if not changes_made: + break + return radii + +def apply_force_directed_relaxation(centers, iterations, step_size, repulsion_strength, repulsion_threshold, boundary_strength, boundary_margin): + """ + Applies a force-directed relaxation algorithm to settle circle centers. + Circles repel each other and are repelled by boundaries. + """ + n = centers.shape[0] + for _ in range(iterations): + forces = np.zeros_like(centers) + for i in range(n): + # Circle-circle repulsion + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + # Boundary repulsion + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + centers += step_size * forces + centers = np.clip(centers, 0.0, 1.0) + return centers + +class CirclePacker: + """ + Encapsulates the logic for constructing a high-density arrangement of circles + using an asymmetric grid initialization, a pre-optimization force-directed + relaxation, and a Simulated Annealing local search with adaptive perturbations. + Combines features from high-performing ancestors. + """ + def __init__(self, n): + self.n = n + self.centers = np.zeros((n, 2)) + self.radii = np.zeros(n) + self.sum_radii = 0.0 + + def _initialize_centers(self): + """ + Initializes circle centers using a Gaussian-deformed grid for 25 circles + and places the 26th in an asymmetric void (from Program 2 / high-performing ancestor). + """ + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + void_center = np.array([0.4, 0.2]) # From high-performing ancestor + amplitude = 0.06 # From high-performing ancestor + sigma = 0.15 # From high-performing ancestor + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + self.centers[:25] = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + def _select_circle_for_perturbation(self, current_radii, current_centers): + """ + Selects a circle to perturb based on its inverse radius, proximity to boundaries, + and local crowding (combining Program 1 and 2 heuristics). + """ + inverse_radii = 1 / (current_radii + 1e-8) + + dist_to_nearest_boundary = np.min([current_centers[:, 0], 1 - current_centers[:, 0], + current_centers[:, 1], 1 - current_centers[:, 1]], axis=0) + boundary_proximity_weight_multiplier = np.exp(-dist_to_nearest_boundary / 0.07) + + # Local Crowding Metric (from Program 1) - helps prioritize circles in dense regions + crowding_metric = np.zeros(self.n) + crowding_threshold = 0.25 # Distance threshold to consider another circle 'crowding' + for i in range(self.n): + distances_to_others = np.linalg.norm(current_centers[i] - np.delete(current_centers, i, axis=0), axis=1) + crowding_metric[i] = np.sum(distances_to_others < crowding_threshold) + + max_crowding = self.n - 1 # Maximum possible neighbors + normalized_crowding = crowding_metric / max_crowding if max_crowding > 0 else np.zeros(self.n) + crowding_influence_factor = 0.8 # How much crowding influences selection (tuneable) + + # Combine all weights: inverse radii * boundary proximity * crowding + combined_weights = inverse_radii * (1 + boundary_proximity_weight_multiplier) * (1 + crowding_influence_factor * normalized_crowding) + selection_probs = combined_weights / np.sum(combined_weights) + circle_idx = np.random.choice(self.n, p=selection_probs) + return circle_idx + + def _get_adaptive_perturb_strength(self, global_perturb_strength, circle_idx, current_radii): + """ + Calculates an adaptive perturbation strength for a specific circle. + Smaller circles receive a proportionally larger perturbation (from Program 2). + """ + max_r = np.max(current_radii) + 1e-8 # Avoid division by zero + relative_radius = current_radii[circle_idx] / max_r + perturb_factor = 1.0 + (1.0 - relative_radius) * 2.0 # More aggressive movement for smaller circles + return global_perturb_strength * perturb_factor + + def pack(self): + """ + Executes the full packing process: initialization, pre-optimization, + and Simulated Annealing with advanced heuristics. + """ + self._initialize_centers() + + # Pre-optimization with F-D relaxation using aggressive parameters from the best previous result (2.39 score) + self.centers = apply_force_directed_relaxation( + self.centers.copy(), + iterations=800, # Increased iterations for more thorough settling + step_size=0.0015, # Increased step size for more movement + repulsion_strength=0.015, # Increased repulsion strength + repulsion_threshold=0.22, # Increased threshold for broader initial spread + boundary_strength=0.08, # Increased boundary repulsion + boundary_margin=0.03 # Maintained + ) + self.radii = compute_max_radii(self.centers) + self.sum_radii = np.sum(self.radii) + + # Initialize current and best states for Simulated Annealing + best_centers = self.centers.copy() + best_radii = self.radii.copy() + best_sum_radii = self.sum_radii + + current_centers = self.centers.copy() + current_radii = self.radii.copy() + current_sum_radii = self.sum_radii + + # SA parameters + total_iterations = 20000 # Increased total iterations for more exploration + initial_global_perturb_strength_base = 0.05 # Slightly higher initial perturb for broader search + final_global_perturb_strength = 0.0002 # Slightly lower final perturb for finer tuning + T_initial = 0.25 # Increased initial temperature for broader initial acceptance + T_final = 1e-8 # Lower final temperature for very greedy behavior at the end + + # Stagnation escape mechanism parameters + no_improvement_count = 0 + max_no_improvement_steps = 500 + current_initial_perturb = initial_global_perturb_strength_base + stagnation_boost_active_counter = 0 + stagnation_boost_duration = 200 + stagnation_aggressive_perturb_multiplier = 2.0 + + # Cluster perturbation probability (Recommendation 2) + cluster_perturb_prob = 0.20 # Increased chance for multi-circle moves + + for iteration in range(total_iterations): + # Annealing schedules + global_perturb_strength = current_initial_perturb * (1 - iteration / total_iterations) + final_global_perturb_strength * (iteration / total_iterations) + + # Apply temporary aggressive perturbation if in stagnation escape + if stagnation_boost_active_counter > 0: + global_perturb_strength *= stagnation_aggressive_perturb_multiplier + stagnation_boost_active_counter -= 1 + + # Temperature decays exponentially + temperature = T_initial * (T_final / T_initial)**(iteration / total_iterations) + + candidate_centers = current_centers.copy() + + # Determine adaptive compute_max_radii iterations (Recommendation 3) + # Starts with fewer iterations, increases precision as temperature drops + min_radii_iter = 100 + max_radii_iter = 750 + # Linearly increase iterations as temperature drops + current_radii_iterations = int(max_radii_iter - (max_radii_iter - min_radii_iter) * (temperature / T_initial)) + if current_radii_iterations < 1: current_radii_iterations = 1 # Ensure at least 1 iteration + + # Multi-modal perturbation choice: cluster or single circle + if np.random.rand() < cluster_perturb_prob: + primary_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster + + # Find closest neighbors to form a cluster + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [primary_idx] + num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + # Apply a coordinated, smaller displacement to the entire cluster + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move + + # Generate a single random direction for the entire cluster + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle if no neighbors for cluster (e.g., n=1) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case, using adaptive selection and strength) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + # Evaluate candidate configuration using adaptive iterations for compute_max_radii + candidate_radii = compute_max_radii(candidate_centers, current_radii_iterations) + candidate_sum_radii = np.sum(candidate_radii) + + # Simulated Annealing acceptance criteria + accepted = False + delta = candidate_sum_radii - current_sum_radii + # Accept better solutions or worse solutions with probability based on temperature + if delta > 0 or (temperature > 1e-10 and np.random.rand() < math.exp(delta / temperature)): + current_sum_radii = candidate_sum_radii + current_centers = candidate_centers.copy() + current_radii = candidate_radii.copy() + accepted = True + + # Update best solution and manage stagnation + if current_sum_radii > best_sum_radii: + best_sum_radii = current_sum_radii + best_centers = current_centers.copy() + best_radii = current_radii.copy() + no_improvement_count = 0 # Reset on new best solution + elif not accepted: + no_improvement_count += 1 + # If stagnated for max_no_improvement_steps, activate escape mechanism + if no_improvement_count > max_no_improvement_steps: + current_initial_perturb *= 1.1 # Small permanent boost to exploration potential + stagnation_boost_active_counter = stagnation_boost_duration # Activate temporary aggressive boost + no_improvement_count = 0 + + return best_centers, best_radii + +def construct_packing(): + """ + Main function to construct the circle packing. + Initializes CirclePacker and runs its packing method. + """ + packer = CirclePacker(n=26) + return packer.pack() +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..a39d12d078e2ba4bee4145df55572a7389df0b4c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_197/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_197/results +Run 1/1 completed in 65.87 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 2.346978649159883 + public: {'centers_str': ' centers[0] = (0.4376, 0.1337)\n centers[1] = (0.3510, 0.7204)\n centers[2] = (0.1061, 0.2051)\n centers[3] = (0.6768, 0.5571)\n centers[4] = (0.7075, 0.3138)\n centers[5] = (0.0893, 0.8507)\n centers[6] = (0.9141, 0.2490)\n centers[7] = (0.8255, 0.9381)\n centers[8] = (0.9603, 0.3659)\n centers[9] = (0.2286, 0.3638)\n centers[10] = (0.4309, 0.5393)\n centers[11] = (0.4191, 0.9628)\n centers[12] = (0.5664, 0.8178)\n centers[13] = (0.4313, 0.3009)\n centers[14] = (0.7426, 0.0932)\n centers[15] = (0.2893, 0.8861)\n centers[16] = (0.8907, 0.4977)\n centers[17] = (0.1542, 0.6155)\n centers[18] = (0.2806, 0.1256)\n centers[19] = (0.9430, 0.9201)\n centers[20] = (0.7242, 0.9584)\n centers[21] = (0.0643, 0.4088)\n centers[22] = (0.8634, 0.7424)\n centers[23] = (0.5578, 0.1412)\n centers[24] = (0.4394, 0.0511)\n centers[25] = (0.9168, 0.0815)', 'num_circles': 26} + private: {'reported_sum_of_radii': 2.346978649159883} + visualization_path: + execution_time_mean: 65.86757605755702 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..f8b88c3eca1e9dd0149bc5f7961795871175becc --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 2.346978649159883, + "public": { + "centers_str": " centers[0] = (0.4376, 0.1337)\n centers[1] = (0.3510, 0.7204)\n centers[2] = (0.1061, 0.2051)\n centers[3] = (0.6768, 0.5571)\n centers[4] = (0.7075, 0.3138)\n centers[5] = (0.0893, 0.8507)\n centers[6] = (0.9141, 0.2490)\n centers[7] = (0.8255, 0.9381)\n centers[8] = (0.9603, 0.3659)\n centers[9] = (0.2286, 0.3638)\n centers[10] = (0.4309, 0.5393)\n centers[11] = (0.4191, 0.9628)\n centers[12] = (0.5664, 0.8178)\n centers[13] = (0.4313, 0.3009)\n centers[14] = (0.7426, 0.0932)\n centers[15] = (0.2893, 0.8861)\n centers[16] = (0.8907, 0.4977)\n centers[17] = (0.1542, 0.6155)\n centers[18] = (0.2806, 0.1256)\n centers[19] = (0.9430, 0.9201)\n centers[20] = (0.7242, 0.9584)\n centers[21] = (0.0643, 0.4088)\n centers[22] = (0.8634, 0.7424)\n centers[23] = (0.5578, 0.1412)\n centers[24] = (0.4394, 0.0511)\n centers[25] = (0.9168, 0.0815)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 2.346978649159883 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_197/results/packing_viz.png", + "execution_time_mean": 65.86757605755702, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..2f76601bba7e8b5cc8a31aada374ddd586d62929 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_197/search_replace.txt @@ -0,0 +1,154 @@ +My analysis of the current packing reveals several areas for improvement. While the overall distribution is decent, there are noticeable gaps and some small circles appear trapped in locations that could be better utilized by larger circles, indicating the search has settled into a local optimum. The arrangement lacks the tight, crystalline structure often seen in optimal packings. + +To break out of these inefficient configurations, I propose a significant enhancement to the search algorithm: a **swap perturbation**. This new move type will complement the existing single-circle and cluster perturbations. Specifically, it will identify a small circle (from the bottom quartile of radii) and a large circle (from the top quartile) and swap their positions. This is a large-scale, "non-local" move designed to fundamentally restructure the packing and unlock configurations that are unreachable by small, local adjustments. + +To accommodate this more disruptive search operator, I am also tuning the Simulated Annealing parameters to be more exploratory. I will increase the total iterations and the initial temperature to allow the system to accept these radical changes and find new, more promising regions of the solution space before cooling down for fine-tuning. + + +add_swap_perturbation + + +My main idea is to introduce a "swap" perturbation to escape deep local minima, which seem to be the main issue in the current visualization (small circles trapped in valuable space). This new move has a 5% chance of swapping a small circle (from the bottom quartile of radii) with a large one (from the top quartile), which can drastically reconfigure the packing and unlock new, better states. + +To support this disruptive move, I'm also tuning the Simulated Annealing parameters: +1. Increasing `total_iterations` to 25,000 to allow more time for the system to settle after a swap. +2. Increasing `T_initial` to 0.3 to raise the initial acceptance probability of such large changes. +3. Decreasing `final_global_perturb_strength` to 0.0001 for more precise fine-tuning at the very end. + +This combines a powerful new search operator with parameter adjustments to create a more robust and effective optimization process. + + +<<<<<<< SEARCH + # SA parameters + total_iterations = 20000 # Increased total iterations for more exploration + initial_global_perturb_strength_base = 0.05 # Slightly higher initial perturb for broader search + final_global_perturb_strength = 0.0002 # Slightly lower final perturb for finer tuning + T_initial = 0.25 # Increased initial temperature for broader initial acceptance + T_final = 1e-8 # Lower final temperature for very greedy behavior at the end +======= + # SA parameters, tuned for new swap perturbation + total_iterations = 25000 # More iterations to settle after big swaps + initial_global_perturb_strength_base = 0.05 # Maintained initial perturb for broader search + final_global_perturb_strength = 0.0001 # Finer tuning at the end + T_initial = 0.3 # Higher temperature to accept disruptive swaps + T_final = 1e-8 # Lower final temperature for very greedy behavior at the end +>>>>>>> REPLACE + + +<<<<<<< SEARCH + # Cluster perturbation probability (Recommendation 2) + cluster_perturb_prob = 0.20 # Increased chance for multi-circle moves +======= + # Perturbation probabilities for multi-modal search + swap_prob = 0.05 + cluster_perturb_prob = 0.20 +>>>>>>> REPLACE + + +<<<<<<< SEARCH + # Multi-modal perturbation choice: cluster or single circle + if np.random.rand() < cluster_perturb_prob: + primary_idx = np.random.choice(self.n) # Randomly pick a starting circle for the cluster + + # Find closest neighbors to form a cluster + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [primary_idx] + num_neighbors_to_include = np.random.choice([1, 2]) # Include 1 or 2 closest neighbors + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + # Apply a coordinated, smaller displacement to the entire cluster + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb # Smaller displacement for coordinated move + + # Generate a single random direction for the entire cluster + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle if no neighbors for cluster (e.g., n=1) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: # Single circle perturbation (most common case, using adaptive selection and strength) + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) +======= + # --- Multi-modal perturbation: Swap, Cluster, or Single --- + rand_val = np.random.rand() + + if rand_val < swap_prob: + # SWAP MOVE: Swap a small circle with a large one to escape local minima. + sorted_radii_indices = np.argsort(current_radii) + quartile_size = self.n // 4 + swap_successful = False + if quartile_size > 0: + small_circle_idx_pool = sorted_radii_indices[:quartile_size] + large_circle_idx_pool = sorted_radii_indices[-quartile_size:] + + idx1 = np.random.choice(small_circle_idx_pool) + idx2 = np.random.choice(large_circle_idx_pool) + + if idx1 != idx2: + # Swap the center positions + candidate_centers[[idx1, idx2]] = candidate_centers[[idx2, idx1]] + swap_successful = True + + if not swap_successful: + # Fallback to single perturbation if swap is not possible or fails + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + elif rand_val < swap_prob + cluster_perturb_prob: + # CLUSTER MOVE: Coordinated move of a few neighboring circles. + primary_idx = np.random.choice(self.n) + + all_indices = np.arange(self.n) + other_indices = np.delete(all_indices, primary_idx) + + if len(other_indices) > 0: + distances = np.linalg.norm(current_centers[primary_idx] - current_centers[other_indices], axis=1) + sorted_neighbor_indices = other_indices[np.argsort(distances)] + + cluster_indices = [primary_idx] + num_neighbors_to_include = np.random.choice([1, 2]) + for i in range(min(num_neighbors_to_include, len(sorted_neighbor_indices))): + cluster_indices.append(sorted_neighbor_indices[i]) + + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, primary_idx, current_radii) + cluster_displacement_magnitude = 0.5 * eff_perturb + + angle = np.random.uniform(0, 2 * np.pi) + direction = np.array([math.cos(angle), math.sin(angle)]) + cluster_displacement = cluster_displacement_magnitude * direction + + for c_idx in cluster_indices: + candidate_centers[c_idx] = np.clip(candidate_centers[c_idx] + cluster_displacement, 0.0, 1.0) + else: # Fallback to single circle move + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) + + else: + # SINGLE CIRCLE MOVE: Default adaptive perturbation. + circle_idx = self._select_circle_for_perturbation(current_radii, current_centers) + eff_perturb = self._get_adaptive_perturb_strength(global_perturb_strength, circle_idx, current_radii) + displacement = np.random.uniform(-eff_perturb, eff_perturb, 2) + candidate_centers[circle_idx] = np.clip(candidate_centers[circle_idx] + displacement, 0.0, 1.0) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0951fc5c1ac14dfcc68d3fcf67bbd9aff17ad88 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..4bf183f29a37e0fe2d6babe15828142bf0ec2b0b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/edit.diff @@ -0,0 +1,153 @@ +--- a/original.py ++++ b/original.py +@@ -1,94 +1,135 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + +- # Place circles in a structured pattern +- # This is a simple pattern - evolution will improve this ++ # Place circles in a staggered grid pattern to improve density ++ # This pattern aims for a more uniform distribution than concentric rings + +- # First, place a large circle in the center +- centers[0] = [0.5, 0.5] ++ num_rows = 5 # Number of rows for the staggered grid ++ # Distribute 26 circles into these rows, with some staggering ++ # This specific distribution attempts to maximize space utilization ++ row_counts = [5, 6, 5, 6, 4] # Total: 5 + 6 + 5 + 6 + 4 = 26 circles + +- # Place 8 circles around it in a ring +- for i in range(8): +- angle = 2 * np.pi * i / 8 +- centers[i + 1] = [0.5 + 0.3 * np.cos(angle), 0.5 + 0.3 * np.sin(angle)] ++ # Calculate vertical spacing for rows. Centers will be placed at y_start + (row_idx + 0.5) * y_interval ++ y_interval = 1.0 / (num_rows + 1) + +- # Place 16 more circles in an outer ring +- for i in range(16): +- angle = 2 * np.pi * i / 16 +- centers[i + 9] = [0.5 + 0.7 * np.cos(angle), 0.5 + 0.7 * np.sin(angle)] ++ # Determine the maximum number of circles in any row to set a consistent x-shift for staggering ++ max_circles_in_row = max(row_counts) # This is 6 + +- # Additional positioning adjustment to make sure all circles +- # are inside the square and don't overlap +- # Clip to ensure everything is inside the unit square ++ idx = 0 ++ for r_idx, count_in_row in enumerate(row_counts): ++ current_y = (r_idx + 1) * y_interval # Centers are at y_interval * 1, 2, ..., num_rows ++ ++ # Define x-positions for circles in the current row ++ # Start with a small margin (e.g., 0.05) to allow for some radius ++ initial_x_margin = 0.05 ++ x_positions_for_row = np.linspace(initial_x_margin, 1.0 - initial_x_margin, count_in_row) ++ ++ # Apply staggering to every other row ++ if r_idx % 2 == 1: # Stagger rows 1 and 3 (0-indexed) ++ # Shift by half of the average x spacing, derived from the row with max circles ++ # This makes the staggering more consistent ++ shift_amount = (1.0 / (max_circles_in_row + 1)) / 2.0 ++ x_positions_for_row += shift_amount ++ ++ # After shifting, ensure centers remain within the acceptable range [initial_x_margin, 1-initial_x_margin] ++ # Rescale if necessary to keep them contained and maintain symmetry ++ min_x_val = np.min(x_positions_for_row) ++ max_x_val = np.max(x_positions_for_row) ++ ++ # If the shifted row goes outside the initial margins, rescale it to fit ++ if min_x_val < initial_x_margin or max_x_val > (1.0 - initial_x_margin): ++ target_range_width = (1.0 - initial_x_margin) - initial_x_margin ++ current_range_width = max_x_val - min_x_val ++ ++ # Avoid division by zero if all circles are at the same point (shouldn't happen here) ++ if current_range_width > 1e-6: ++ scale_factor = target_range_width / current_range_width ++ x_positions_for_row = (x_positions_for_row - min_x_val) * scale_factor + initial_x_margin ++ else: # Fallback for extreme cases, just center them ++ x_positions_for_row = np.full_like(x_positions_for_row, 0.5) ++ ++ # Populate the centers array ++ for x_val in x_positions_for_row: ++ if idx < n: # Safety check, should always be true here ++ centers[idx] = [x_val, current_y] ++ idx += 1 ++ else: ++ break # All circles placed ++ if idx >= n: ++ break ++ ++ # Clip to ensure everything is inside the unit square. Our placement aims to keep ++ # centers within [0.05, 0.95], which is stricter than [0.01, 0.99], so this clip ++ # will primarily serve as a safety measure and honor the original code's intent. + centers = np.clip(centers, 0.01, 0.99) + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/main.py new file mode 100644 index 0000000000000000000000000000000000000000..27c7514b6f120e1038493e95caa4b98ae5de86b4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/main.py @@ -0,0 +1,135 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Place circles in a staggered grid pattern to improve density + # This pattern aims for a more uniform distribution than concentric rings + + num_rows = 5 # Number of rows for the staggered grid + # Distribute 26 circles into these rows, with some staggering + # This specific distribution attempts to maximize space utilization + row_counts = [5, 6, 5, 6, 4] # Total: 5 + 6 + 5 + 6 + 4 = 26 circles + + # Calculate vertical spacing for rows. Centers will be placed at y_start + (row_idx + 0.5) * y_interval + y_interval = 1.0 / (num_rows + 1) + + # Determine the maximum number of circles in any row to set a consistent x-shift for staggering + max_circles_in_row = max(row_counts) # This is 6 + + idx = 0 + for r_idx, count_in_row in enumerate(row_counts): + current_y = (r_idx + 1) * y_interval # Centers are at y_interval * 1, 2, ..., num_rows + + # Define x-positions for circles in the current row + # Start with a small margin (e.g., 0.05) to allow for some radius + initial_x_margin = 0.05 + x_positions_for_row = np.linspace(initial_x_margin, 1.0 - initial_x_margin, count_in_row) + + # Apply staggering to every other row + if r_idx % 2 == 1: # Stagger rows 1 and 3 (0-indexed) + # Shift by half of the average x spacing, derived from the row with max circles + # This makes the staggering more consistent + shift_amount = (1.0 / (max_circles_in_row + 1)) / 2.0 + x_positions_for_row += shift_amount + + # After shifting, ensure centers remain within the acceptable range [initial_x_margin, 1-initial_x_margin] + # Rescale if necessary to keep them contained and maintain symmetry + min_x_val = np.min(x_positions_for_row) + max_x_val = np.max(x_positions_for_row) + + # If the shifted row goes outside the initial margins, rescale it to fit + if min_x_val < initial_x_margin or max_x_val > (1.0 - initial_x_margin): + target_range_width = (1.0 - initial_x_margin) - initial_x_margin + current_range_width = max_x_val - min_x_val + + # Avoid division by zero if all circles are at the same point (shouldn't happen here) + if current_range_width > 1e-6: + scale_factor = target_range_width / current_range_width + x_positions_for_row = (x_positions_for_row - min_x_val) * scale_factor + initial_x_margin + else: # Fallback for extreme cases, just center them + x_positions_for_row = np.full_like(x_positions_for_row, 0.5) + + # Populate the centers array + for x_val in x_positions_for_row: + if idx < n: # Safety check, should always be true here + centers[idx] = [x_val, current_y] + idx += 1 + else: + break # All circles placed + if idx >= n: + break + + # Clip to ensure everything is inside the unit square. Our placement aims to keep + # centers within [0.05, 0.95], which is stricter than [0.01, 0.99], so this clip + # will primarily serve as a safety measure and honor the original code's intent. + centers = np.clip(centers, 0.01, 0.99) + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/original.py new file mode 100644 index 0000000000000000000000000000000000000000..f52133ed39da8e9d823b52b994ee5063132aad94 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/original.py @@ -0,0 +1,94 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Place circles in a structured pattern + # This is a simple pattern - evolution will improve this + + # First, place a large circle in the center + centers[0] = [0.5, 0.5] + + # Place 8 circles around it in a ring + for i in range(8): + angle = 2 * np.pi * i / 8 + centers[i + 1] = [0.5 + 0.3 * np.cos(angle), 0.5 + 0.3 * np.sin(angle)] + + # Place 16 more circles in an outer ring + for i in range(16): + angle = 2 * np.pi * i / 16 + centers[i + 9] = [0.5 + 0.7 * np.cos(angle), 0.5 + 0.7 * np.sin(angle)] + + # Additional positioning adjustment to make sure all circles + # are inside the square and don't overlap + # Clip to ensure everything is inside the unit square + centers = np.clip(centers, 0.01, 0.99) + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..bd510a056d8d598ca54f91339bcde9214859d50b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_2/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_2/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.396383336501379 + public: {'centers_str': ' centers[0] = (0.0500, 0.1667)\n centers[1] = (0.2750, 0.1667)\n centers[2] = (0.5000, 0.1667)\n centers[3] = (0.7250, 0.1667)\n centers[4] = (0.9500, 0.1667)\n centers[5] = (0.0500, 0.3333)\n centers[6] = (0.2300, 0.3333)\n centers[7] = (0.4100, 0.3333)\n centers[8] = (0.5900, 0.3333)\n centers[9] = (0.7700, 0.3333)\n centers[10] = (0.9500, 0.3333)\n centers[11] = (0.0500, 0.5000)\n centers[12] = (0.2750, 0.5000)\n centers[13] = (0.5000, 0.5000)\n centers[14] = (0.7250, 0.5000)\n centers[15] = (0.9500, 0.5000)\n centers[16] = (0.0500, 0.6667)\n centers[17] = (0.2300, 0.6667)\n centers[18] = (0.4100, 0.6667)\n centers[19] = (0.5900, 0.6667)\n centers[20] = (0.7700, 0.6667)\n centers[21] = (0.9500, 0.6667)\n centers[22] = (0.0500, 0.8333)\n centers[23] = (0.3500, 0.8333)\n centers[24] = (0.6500, 0.8333)\n centers[25] = (0.9500, 0.8333)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.396383336501379} + visualization_path: + execution_time_mean: 0.002916187047958374 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..9579e87cf6e553a7bc26c0c0ae6283f258e40dc2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.396383336501379, + "public": { + "centers_str": " centers[0] = (0.0500, 0.1667)\n centers[1] = (0.2750, 0.1667)\n centers[2] = (0.5000, 0.1667)\n centers[3] = (0.7250, 0.1667)\n centers[4] = (0.9500, 0.1667)\n centers[5] = (0.0500, 0.3333)\n centers[6] = (0.2300, 0.3333)\n centers[7] = (0.4100, 0.3333)\n centers[8] = (0.5900, 0.3333)\n centers[9] = (0.7700, 0.3333)\n centers[10] = (0.9500, 0.3333)\n centers[11] = (0.0500, 0.5000)\n centers[12] = (0.2750, 0.5000)\n centers[13] = (0.5000, 0.5000)\n centers[14] = (0.7250, 0.5000)\n centers[15] = (0.9500, 0.5000)\n centers[16] = (0.0500, 0.6667)\n centers[17] = (0.2300, 0.6667)\n centers[18] = (0.4100, 0.6667)\n centers[19] = (0.5900, 0.6667)\n centers[20] = (0.7700, 0.6667)\n centers[21] = (0.9500, 0.6667)\n centers[22] = (0.0500, 0.8333)\n centers[23] = (0.3500, 0.8333)\n centers[24] = (0.6500, 0.8333)\n centers[25] = (0.9500, 0.8333)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.396383336501379 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_2/results/packing_viz.png", + "execution_time_mean": 0.002916187047958374, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3e6cb8939f93a6fb0133238e9c104b42a22f209 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_2/search_replace.txt @@ -0,0 +1,88 @@ +staggered_grid_placement +Replace the current ring-based circle placement with a staggered grid pattern. The original placement led to a duplicate circle and many circles being pushed out of bounds then clipped, resulting in very small radii. The new pattern distributes 26 circles into 5 rows (5, 6, 5, 6, 4 circles per row) with vertical and horizontal staggering. This aims for a more uniform and denser initial packing, ensuring all centers are distinct and within reasonable boundaries, which should significantly improve the sum of radii. + +<<<<<<< SEARCH + # Place circles in a structured pattern + # This is a simple pattern - evolution will improve this + + # First, place a large circle in the center + centers[0] = [0.5, 0.5] + + # Place 8 circles around it in a ring + for i in range(8): + angle = 2 * np.pi * i / 8 + centers[i + 1] = [0.5 + 0.3 * np.cos(angle), 0.5 + 0.3 * np.sin(angle)] + + # Place 16 more circles in an outer ring + for i in range(16): + angle = 2 * np.pi * i / 16 + centers[i + 9] = [0.5 + 0.7 * np.cos(angle), 0.5 + 0.7 * np.sin(angle)] + + # Additional positioning adjustment to make sure all circles + # are inside the square and don't overlap + # Clip to ensure everything is inside the unit square + centers = np.clip(centers, 0.01, 0.99) +======= + # Place circles in a staggered grid pattern to improve density + # This pattern aims for a more uniform distribution than concentric rings + + num_rows = 5 # Number of rows for the staggered grid + # Distribute 26 circles into these rows, with some staggering + # This specific distribution attempts to maximize space utilization + row_counts = [5, 6, 5, 6, 4] # Total: 5 + 6 + 5 + 6 + 4 = 26 circles + + # Calculate vertical spacing for rows. Centers will be placed at y_start + (row_idx + 0.5) * y_interval + y_interval = 1.0 / (num_rows + 1) + + # Determine the maximum number of circles in any row to set a consistent x-shift for staggering + max_circles_in_row = max(row_counts) # This is 6 + + idx = 0 + for r_idx, count_in_row in enumerate(row_counts): + current_y = (r_idx + 1) * y_interval # Centers are at y_interval * 1, 2, ..., num_rows + + # Define x-positions for circles in the current row + # Start with a small margin (e.g., 0.05) to allow for some radius + initial_x_margin = 0.05 + x_positions_for_row = np.linspace(initial_x_margin, 1.0 - initial_x_margin, count_in_row) + + # Apply staggering to every other row + if r_idx % 2 == 1: # Stagger rows 1 and 3 (0-indexed) + # Shift by half of the average x spacing, derived from the row with max circles + # This makes the staggering more consistent + shift_amount = (1.0 / (max_circles_in_row + 1)) / 2.0 + x_positions_for_row += shift_amount + + # After shifting, ensure centers remain within the acceptable range [initial_x_margin, 1-initial_x_margin] + # Rescale if necessary to keep them contained and maintain symmetry + min_x_val = np.min(x_positions_for_row) + max_x_val = np.max(x_positions_for_row) + + # If the shifted row goes outside the initial margins, rescale it to fit + if min_x_val < initial_x_margin or max_x_val > (1.0 - initial_x_margin): + target_range_width = (1.0 - initial_x_margin) - initial_x_margin + current_range_width = max_x_val - min_x_val + + # Avoid division by zero if all circles are at the same point (shouldn't happen here) + if current_range_width > 1e-6: + scale_factor = target_range_width / current_range_width + x_positions_for_row = (x_positions_for_row - min_x_val) * scale_factor + initial_x_margin + else: # Fallback for extreme cases, just center them + x_positions_for_row = np.full_like(x_positions_for_row, 0.5) + + # Populate the centers array + for x_val in x_positions_for_row: + if idx < n: # Safety check, should always be true here + centers[idx] = [x_val, current_y] + idx += 1 + else: + break # All circles placed + if idx >= n: + break + + # Clip to ensure everything is inside the unit square. Our placement aims to keep + # centers within [0.05, 0.95], which is stricter than [0.01, 0.99], so this clip + # will primarily serve as a safety measure and honor the original code's intent. + centers = np.clip(centers, 0.01, 0.99) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..d689671ffc031a4da26af2610250c9ea3b106889 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/edit.diff @@ -0,0 +1,123 @@ +--- a/original.py ++++ b/original.py +@@ -1,102 +1,34 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" ++ ++staggered_row_packing ++ + +-import numpy as np ++ ++This program proposes a new arrangement for 26 circles within the unit square. Instead of starting with a 5x5 grid and adding a 26th circle in an interstitial void, which caused highly uneven radius distribution and small radii for surrounding circles (as observed in the provided visualization), this approach constructs a configuration specifically designed for 26 circles from the outset. + ++The proposed pattern is a staggered row arrangement: ++- Five rows of circles are used, with their y-coordinates evenly spaced using `np.linspace(0.1, 0.9, 5)`. ++- The number of circles in each row alternates between 5, 6, 5, 6, and 4 (totaling 26 circles: 5+6+5+6+4=26). ++- For rows with 5 circles, x-coordinates are `np.linspace(0.1, 0.9, 5)`. ++- For rows with 6 circles, x-coordinates are `np.linspace(0.08, 0.92, 6)`, making them slightly denser horizontally to allow for potentially larger radii due to a tighter packing. ++- For the row with 4 circles, x-coordinates are `np.linspace(0.2, 0.8, 4)`, placing them centrally within the available horizontal space. + +-def construct_packing(): +- """ +- Construct a specific arrangement of 26 circles in a unit square +- that attempts to maximize the sum of their radii. ++This construction aims to: ++1. **Improve Spatial Distribution:** By using an alternating number of circles per row and slightly different x-spacings, the packing is more akin to a quasi-hexagonal arrangement, which is generally denser and distributes constraints more evenly than a simple square grid. ++2. **Avoid Inefficient Patterns:** This method avoids creating localized "bottlenecks" where a single extra circle severely constrains its neighbors, which was the primary issue with the previous `5x5 + one at (0.2, 0.2)` setup (visualized by the very small circles around `(0.2, 0.2)`). ++3. **Better Edge Utilization:** The `linspace` ranges (e.g., `0.1` to `0.9` or `0.08` to `0.92`) are chosen to ensure circles are close to the boundaries, utilizing the edges effectively. + +- Returns: +- Tuple of (centers, radii, sum_of_radii) +- centers: np.array of shape (26, 2) with (x, y) coordinates +- radii: np.array of shape (26) with radius of each circle +- sum_of_radii: Sum of all radii +- """ +- # Initialize arrays for 26 circles +- n = 26 +- centers = np.zeros((n, 2)) ++The `compute_max_radii` function remains unchanged, as it is a robust iterative solver for finding maximum non-overlapping radii given a set of center points. The improvement relies entirely on providing a better initial `centers` configuration. ++ + +- # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), +- # which provides a very strong and dense foundation. +- # The 26th circle is then placed in a central interstitial void. +- +- # 1. Place 25 circles in a 5x5 grid. +- # This is the known optimal packing for 25 equal circles. +- x_coords_5 = np.linspace(0.1, 0.9, 5) +- y_coords_5 = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords_5, y_coords_5) +- centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T +- +- # 2. Place the 26th circle in a promising interstitial position. +- # The voids in a 5x5 grid are at positions like (0.2, 0.2), (0.2, 0.4), etc. +- # Placing it at (0.4, 0.4) puts it in a central void, surrounded by +- # circles at (0.1, 0.1), (0.3, 0.1), (0.1, 0.3), and (0.3, 0.3). +- # Placing the circle in a corner void may be less disruptive to the overall +- # packing as it primarily affects already-constrained edge circles. +- centers[25] = [0.2, 0.2] +- +- # Compute maximum valid radii for this configuration +- radii = compute_max_radii(centers) +- return centers, radii +- +- +-def compute_max_radii(centers): +- """ +- Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This version +- iteratively resolves conflicts until convergence for a more accurate result. +- +- Args: +- centers: np.array of shape (n, 2) with (x, y) coordinates +- +- Returns: +- np.array of shape (n) with radius of each circle +- """ +- n = centers.shape[0] +- radii = np.ones(n) +- +- # First, limit by distance to square borders +- for i in range(n): +- x, y = centers[i] +- radii[i] = min(x, y, 1 - x, 1 - y) +- +- # Iteratively limit by distance to other circles, allowing constraints to propagate +- for _ in range(300): # Iterate to ensure convergence +- changes_made = False +- for i in range(n): +- for j in range(i + 1, n): +- dist = np.linalg.norm(centers[i] - centers[j]) +- +- # If current radii cause overlap +- if radii[i] + radii[j] > dist: +- sum_r = radii[i] + radii[j] +- if sum_r > 1e-9: # Avoid division by zero for coincident centers +- # Scale both radii proportionally to resolve overlap +- scale = dist / sum_r +- ri_new = radii[i] * scale +- rj_new = radii[j] * scale +- +- # Check for significant change to set the flag +- if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: +- radii[i] = ri_new +- radii[j] = rj_new +- changes_made = True +- if not changes_made: +- break # Exit early if the configuration is stable +- +- return radii +- +- ++ + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/main.py new file mode 100644 index 0000000000000000000000000000000000000000..8b06ce3564e89cafdf2ad16b7d973a4f7eeec718 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/main.py @@ -0,0 +1,34 @@ +# EVOLVE-BLOCK-START + +staggered_row_packing + + + +This program proposes a new arrangement for 26 circles within the unit square. Instead of starting with a 5x5 grid and adding a 26th circle in an interstitial void, which caused highly uneven radius distribution and small radii for surrounding circles (as observed in the provided visualization), this approach constructs a configuration specifically designed for 26 circles from the outset. + +The proposed pattern is a staggered row arrangement: +- Five rows of circles are used, with their y-coordinates evenly spaced using `np.linspace(0.1, 0.9, 5)`. +- The number of circles in each row alternates between 5, 6, 5, 6, and 4 (totaling 26 circles: 5+6+5+6+4=26). +- For rows with 5 circles, x-coordinates are `np.linspace(0.1, 0.9, 5)`. +- For rows with 6 circles, x-coordinates are `np.linspace(0.08, 0.92, 6)`, making them slightly denser horizontally to allow for potentially larger radii due to a tighter packing. +- For the row with 4 circles, x-coordinates are `np.linspace(0.2, 0.8, 4)`, placing them centrally within the available horizontal space. + +This construction aims to: +1. **Improve Spatial Distribution:** By using an alternating number of circles per row and slightly different x-spacings, the packing is more akin to a quasi-hexagonal arrangement, which is generally denser and distributes constraints more evenly than a simple square grid. +2. **Avoid Inefficient Patterns:** This method avoids creating localized "bottlenecks" where a single extra circle severely constrains its neighbors, which was the primary issue with the previous `5x5 + one at (0.2, 0.2)` setup (visualized by the very small circles around `(0.2, 0.2)`). +3. **Better Edge Utilization:** The `linspace` ranges (e.g., `0.1` to `0.9` or `0.08` to `0.92`) are chosen to ensure circles are close to the boundaries, utilizing the edges effectively. + +The `compute_max_radii` function remains unchanged, as it is a robust iterative solver for finding maximum non-overlapping radii given a set of center points. The improvement relies entirely on providing a better initial `centers` configuration. + + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/original.py new file mode 100644 index 0000000000000000000000000000000000000000..225e352e60a295c9ed99ff3b055cf6bee64371d9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/original.py @@ -0,0 +1,102 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a promising interstitial position. + # The voids in a 5x5 grid are at positions like (0.2, 0.2), (0.2, 0.4), etc. + # Placing it at (0.4, 0.4) puts it in a central void, surrounded by + # circles at (0.1, 0.1), (0.3, 0.1), (0.1, 0.3), and (0.3, 0.3). + # Placing the circle in a corner void may be less disruptive to the overall + # packing as it primarily affects already-constrained edge circles. + centers[25] = [0.2, 0.2] + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..c29a37295a9fbc383c8233e955b2d4fef336a231 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": false, + "error": "invalid decimal literal (main.py, line 7)" +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..8312836a4b105a59726ee9cc46f481f7d95d9eb8 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/job_log.out @@ -0,0 +1,14 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_20/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_20/results +Evaluation error: invalid decimal literal (main.py, line 7) +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/metrics.json +Evaluation or Validation failed: invalid decimal literal (main.py, line 7) +Metrics: + combined_score: 0.0 + execution_time_mean: 0.0 + execution_time_std: 0.0 + num_successful_runs: 0 + num_valid_runs: 0 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..fec2021a6a036637c9d3049ae9778c77cef78421 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/results/metrics.json @@ -0,0 +1,9 @@ +{ + "combined_score": 0.0, + "execution_time_mean": 0.0, + "execution_time_std": 0.0, + "num_successful_runs": 0, + "num_valid_runs": 0, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..93c51ce7975e7b0cfd72cfcd95a57630b290c9fe --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_20/rewrite.txt @@ -0,0 +1,23 @@ + +staggered_row_packing + + + +This program proposes a new arrangement for 26 circles within the unit square. Instead of starting with a 5x5 grid and adding a 26th circle in an interstitial void, which caused highly uneven radius distribution and small radii for surrounding circles (as observed in the provided visualization), this approach constructs a configuration specifically designed for 26 circles from the outset. + +The proposed pattern is a staggered row arrangement: +- Five rows of circles are used, with their y-coordinates evenly spaced using `np.linspace(0.1, 0.9, 5)`. +- The number of circles in each row alternates between 5, 6, 5, 6, and 4 (totaling 26 circles: 5+6+5+6+4=26). +- For rows with 5 circles, x-coordinates are `np.linspace(0.1, 0.9, 5)`. +- For rows with 6 circles, x-coordinates are `np.linspace(0.08, 0.92, 6)`, making them slightly denser horizontally to allow for potentially larger radii due to a tighter packing. +- For the row with 4 circles, x-coordinates are `np.linspace(0.2, 0.8, 4)`, placing them centrally within the available horizontal space. + +This construction aims to: +1. **Improve Spatial Distribution:** By using an alternating number of circles per row and slightly different x-spacings, the packing is more akin to a quasi-hexagonal arrangement, which is generally denser and distributes constraints more evenly than a simple square grid. +2. **Avoid Inefficient Patterns:** This method avoids creating localized "bottlenecks" where a single extra circle severely constrains its neighbors, which was the primary issue with the previous `5x5 + one at (0.2, 0.2)` setup (visualized by the very small circles around `(0.2, 0.2)`). +3. **Better Edge Utilization:** The `linspace` ranges (e.g., `0.1` to `0.9` or `0.08` to `0.92`) are chosen to ensure circles are close to the boundaries, utilizing the edges effectively. + +The `compute_max_radii` function remains unchanged, as it is a robust iterative solver for finding maximum non-overlapping radii given a set of center points. The improvement relies entirely on providing a better initial `centers` configuration. + + + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3adcda09c2b38ac491430fe7708e18d5dac208cd Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..a1cee0c6ad49ebcb43a9e420129351eae79c9ea9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/edit.diff @@ -0,0 +1,159 @@ +--- a/original.py ++++ b/original.py +@@ -1,106 +1,110 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square +- that attempts to maximize the sum of their radii. ++ that attempts to maximize the sum of their radii. This method uses a ++ Gaussian deformation of a 5x5 grid to create space for the 26th circle. + + Returns: +- Tuple of (centers, radii, sum_of_radii) ++ Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle +- sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + +- # Using a 5-5-6-5-5 column-like structure. +- # This structure is inspired by known good packings for N=26 and provides +- # much better space utilization than the previous concentric ring model. +- # It avoids the need for clipping, which created tiny, inefficient circles. ++ # 1. Start with 25 circles in a 5x5 grid (optimal for n=25) ++ x_coords_5 = np.linspace(0.1, 0.9, 5) ++ y_coords_5 = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords_5, y_coords_5) ++ centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + +- # x-coordinates for the 5 columns +- x_cols = np.linspace(0.1, 0.9, 5) ++ # 2. Define a void and apply a Gaussian repulsive force to deform the grid ++ void_center = np.array([0.4, 0.4]) ++ amplitude = 0.04 # Displacement magnitude ++ sigma = 0.15 # Range of the repulsive force + +- # y-coordinates for columns with 5 circles +- y_5 = np.linspace(0.1, 0.9, 5) ++ # Deform the 25 grid points ++ for i in range(25): ++ dist_vec = centers[i] - void_center ++ distance = np.linalg.norm(dist_vec) ++ if distance > 1e-6: ++ unit_vec = dist_vec / distance ++ # Gaussian displacement pushes circles away from the void center ++ displacement = amplitude * np.exp(-distance**2 / (2 * sigma**2)) ++ centers[i] += unit_vec * displacement + +- # y-coordinates for the central column with 6 circles +- y_6 = np.linspace(1/12, 11/12, 6) ++ # 3. Place the 26th circle into the created void ++ centers[25] = void_center + +- count = 0 +- # Arrange circles column by column +- for i in range(5): +- x = x_cols[i] ++ # Clipping is a safeguard against pushing centers outside the square. ++ centers = np.clip(centers, 0.0001, 0.9999) + +- # The central column (i=2) has 6 circles +- if i == 2: +- for y in y_6: +- centers[count] = [x, y] +- count += 1 +- # The other four columns have 5 circles each +- else: +- for y in y_5: +- centers[count] = [x, y] +- count += 1 +- +- # This construction places all centers within the (0,1) square, +- # so no clipping is necessary. +- +- # Compute maximum valid radii for this configuration ++ # Compute maximum valid radii for this new configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. ++ such that they don't overlap and stay within the unit square. This version ++ iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] +- # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + +- # Then, limit by distance to other circles +- # Each pair of circles with centers at distance d can have +- # sum of radii at most d to avoid overlap +- for i in range(n): +- for j in range(i + 1, n): +- dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) ++ # Iteratively limit by distance to other circles, allowing constraints to propagate ++ for _ in range(300): # Iterate to ensure convergence ++ changes_made = False ++ for i in range(n): ++ for j in range(i + 1, n): ++ dist = np.linalg.norm(centers[i] - centers[j]) + +- # If current radii would cause overlap +- if radii[i] + radii[j] > dist: +- # Scale both radii proportionally +- scale = dist / (radii[i] + radii[j]) +- radii[i] *= scale +- radii[j] *= scale ++ # If current radii cause overlap ++ if radii[i] + radii[j] > dist: ++ sum_r = radii[i] + radii[j] ++ if sum_r > 1e-9: # Avoid division by zero for coincident centers ++ # Scale both radii proportionally to resolve overlap ++ scale = dist / sum_r ++ ri_new = radii[i] * scale ++ rj_new = radii[j] * scale ++ ++ # Check for significant change to set the flag ++ if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: ++ radii[i] = ri_new ++ radii[j] = rj_new ++ changes_made = True ++ if not changes_made: ++ break # Exit early if the configuration is stable + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/main.py new file mode 100644 index 0000000000000000000000000000000000000000..89d0dc7fb905d5d62707e0c3aa6a0009737fa2ae --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/main.py @@ -0,0 +1,110 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. This method uses a + Gaussian deformation of a 5x5 grid to create space for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with 25 circles in a 5x5 grid (optimal for n=25) + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define a void and apply a Gaussian repulsive force to deform the grid + void_center = np.array([0.4, 0.4]) + amplitude = 0.04 # Displacement magnitude + sigma = 0.15 # Range of the repulsive force + + # Deform the 25 grid points + for i in range(25): + dist_vec = centers[i] - void_center + distance = np.linalg.norm(dist_vec) + if distance > 1e-6: + unit_vec = dist_vec / distance + # Gaussian displacement pushes circles away from the void center + displacement = amplitude * np.exp(-distance**2 / (2 * sigma**2)) + centers[i] += unit_vec * displacement + + # 3. Place the 26th circle into the created void + centers[25] = void_center + + # Clipping is a safeguard against pushing centers outside the square. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this new configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/original.py new file mode 100644 index 0000000000000000000000000000000000000000..e377c515cfd882e949dd853539d5a7fe0af3f981 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/original.py @@ -0,0 +1,106 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Using a 5-5-6-5-5 column-like structure. + # This structure is inspired by known good packings for N=26 and provides + # much better space utilization than the previous concentric ring model. + # It avoids the need for clipping, which created tiny, inefficient circles. + + # x-coordinates for the 5 columns + x_cols = np.linspace(0.1, 0.9, 5) + + # y-coordinates for columns with 5 circles + y_5 = np.linspace(0.1, 0.9, 5) + + # y-coordinates for the central column with 6 circles + y_6 = np.linspace(1/12, 11/12, 6) + + count = 0 + # Arrange circles column by column + for i in range(5): + x = x_cols[i] + + # The central column (i=2) has 6 circles + if i == 2: + for y in y_6: + centers[count] = [x, y] + count += 1 + # The other four columns have 5 circles each + else: + for y in y_5: + centers[count] = [x, y] + count += 1 + + # This construction places all centers within the (0,1) square, + # so no clipping is necessary. + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..7cc7bfe363a910e449d4921fbc9b330a1cf10499 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_22/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_22/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9617474245900182 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0959)\n centers[2] = (0.5014, 0.0959)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0959, 0.2986)\n centers[6] = (0.2819, 0.2819)\n centers[7] = (0.5181, 0.2819)\n centers[8] = (0.7041, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0959, 0.5014)\n centers[11] = (0.2819, 0.5181)\n centers[12] = (0.5181, 0.5181)\n centers[13] = (0.7041, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7041)\n centers[17] = (0.5014, 0.7041)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9617474245900182} + visualization_path: + execution_time_mean: 0.0027323542162775993 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..29aa1534325e428b612643d65517d411321c9f54 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9617474245900182, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0959)\n centers[2] = (0.5014, 0.0959)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0959, 0.2986)\n centers[6] = (0.2819, 0.2819)\n centers[7] = (0.5181, 0.2819)\n centers[8] = (0.7041, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0959, 0.5014)\n centers[11] = (0.2819, 0.5181)\n centers[12] = (0.5181, 0.5181)\n centers[13] = (0.7041, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7041)\n centers[17] = (0.5014, 0.7041)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9617474245900182 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_22/results/packing_viz.png", + "execution_time_mean": 0.0027323542162775993, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..6c4e82097b9627c18a40e0c3065b1032b536008d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_22/search_replace.txt @@ -0,0 +1,212 @@ +Here are my proposed changes to improve the circle packing configuration. + +### Analysis of the Current Visualization + +1. **Spatial Distribution & Inefficient Patterns:** The current `5-5-6-5-5` column-based arrangement is rigid and inhomogeneous. The visualization clearly shows that circles in the central column (`x=0.5`) are packed much more tightly vertically than circles in the other columns. This forces their radii to be small, creating a bottleneck for the entire packing and wasting space. +2. **Unused Space:** The rigid grid-like structure creates large, rectangular empty regions between the circles. A more efficient packing would stagger the circles, similar to a hexagonal lattice, to minimize these gaps. +3. **Asymmetric Radii (Bug Indication):** The most glaring issue is the severe asymmetry in radii. Circles on the right side are large (yellow), while those on the left are much smaller (blue/green). For a symmetric arrangement of centers, this indicates a fundamental flaw in the `compute_max_radii` function. The single-pass algorithm's result is highly dependent on the order of processing, unfairly penalizing circles with lower indices (in this case, the ones on the left). + +My proposed edits will address these issues in two steps: first by fixing the flawed radius calculation, and second by implementing a much more sophisticated and efficient method for generating the circle centers. + + +fix_radius_calculation + + +The existing `compute_max_radii` function is severely flawed. It uses a single-pass loop to scale down overlapping circle radii, which creates a strong dependency on the order of circles. Circles with lower indices are disproportionately shrunk, leading to a highly asymmetric and suboptimal packing, as seen in the visualization. + +This edit replaces the buggy single-pass implementation with a robust iterative algorithm. The new version loops repeatedly (up to 300 times or until convergence) over all pairs of circles, propagating the constraints until a stable configuration is reached where no radii can be increased. This is the correct way to solve the system of constraints and will provide a much more accurate and fair calculation of the maximum possible radii for any given set of centers. + + +<<<<<<< SEARCH +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii +======= +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii +>>>>>>> REPLACE + + +gaussian_grid_deformation + + +The current `5-5-6-5-5` column layout is rigid and inefficient, creating dense columns next to sparse ones, which limits the overall sum of radii. This edit introduces a more sophisticated construction method based on physics-inspired relaxation. It starts with the optimal 5x5 grid for 25 circles. It then simulates a repulsive force emanating from a central point `(0.4, 0.4)` to deform this grid. The force, modeled with a Gaussian function, pushes nearby circles away, creating a customized void. The 26th circle is then placed in this newly created space. + +This "Gaussian grid deformation" method is superior because it allows the initial packing to flexibly adapt and make room for the additional circle, leading to a much more integrated and dense overall arrangement than simply placing a circle in a static grid. The hyperparameters for the deformation (`amplitude=0.04`, `sigma=0.15`) are chosen to create a significant but localized pocket. This should dramatically improve space utilization and the resulting sum of radii. + + +<<<<<<< SEARCH +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Using a 5-5-6-5-5 column-like structure. + # This structure is inspired by known good packings for N=26 and provides + # much better space utilization than the previous concentric ring model. + # It avoids the need for clipping, which created tiny, inefficient circles. + + # x-coordinates for the 5 columns + x_cols = np.linspace(0.1, 0.9, 5) + + # y-coordinates for columns with 5 circles + y_5 = np.linspace(0.1, 0.9, 5) + + # y-coordinates for the central column with 6 circles + y_6 = np.linspace(1/12, 11/12, 6) + + count = 0 + # Arrange circles column by column + for i in range(5): + x = x_cols[i] + + # The central column (i=2) has 6 circles + if i == 2: + for y in y_6: + centers[count] = [x, y] + count += 1 + # The other four columns have 5 circles each + else: + for y in y_5: + centers[count] = [x, y] + count += 1 + + # This construction places all centers within the (0,1) square, + # so no clipping is necessary. + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii +======= +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. This method uses a + Gaussian deformation of a 5x5 grid to create space for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with 25 circles in a 5x5 grid (optimal for n=25) + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define a void and apply a Gaussian repulsive force to deform the grid + void_center = np.array([0.4, 0.4]) + amplitude = 0.04 # Displacement magnitude + sigma = 0.15 # Range of the repulsive force + + # Deform the 25 grid points + for i in range(25): + dist_vec = centers[i] - void_center + distance = np.linalg.norm(dist_vec) + if distance > 1e-6: + unit_vec = dist_vec / distance + # Gaussian displacement pushes circles away from the void center + displacement = amplitude * np.exp(-distance**2 / (2 * sigma**2)) + centers[i] += unit_vec * displacement + + # 3. Place the 26th circle into the created void + centers[25] = void_center + + # Clipping is a safeguard against pushing centers outside the square. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this new configuration + radii = compute_max_radii(centers) + return centers, radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f74ad40d35c697cbb70f1e5582904fb362b92619 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..cbc2afd799d6105c2c3d9f6abe512069aecf56bb --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/edit.diff @@ -0,0 +1,156 @@ +--- a/original.py ++++ b/original.py +@@ -1,96 +1,135 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" ++"""Constructor-based circle packing for n=26 circles using iterative relaxation""" + + import numpy as np + + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles by building on the +- optimal packing for 25 circles and placing the 26th in an interstitial void. ++ Constructs a high-density arrangement of 26 circles by starting with a ++ grid layout and then iteratively relaxing the positions of the centers ++ based on repulsive forces. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + +- # 1. Place 25 circles in a 5x5 grid. This is the optimal packing for 25 +- # equal circles, providing a strong, high-density baseline. The ideal radius +- # for each circle in this packing is 0.1. ++ # 1. Start with a strong initial configuration: a 5x5 grid (optimal for 25) ++ # and place the 26th circle in an interstitial void. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T +- +- # 2. Place the 26th circle in a central interstitial void. +- # The grid points are at {0.1, 0.3, 0.5, 0.7, 0.9}. The voids are at +- # {0.2, 0.4, 0.6, 0.8}. We choose (0.4, 0.4) as it is one of the +- # most central voids, creating a symmetric disruption. + centers[25] = [0.4, 0.4] + +- # 3. Compute maximum valid radii for this configuration using an iterative +- # and robust calculation method. ++ # 2. Iteratively relax the circle positions using a physics-based model. ++ # This allows the circles to push each other into a more efficient packing. ++ n_iters = 80 # Number of relaxation steps. ++ step_size = 0.002 # How much to move centers per step (learning rate). ++ repulsion_strength = 0.02 # Multiplier for circle-circle repulsion force. ++ boundary_strength = 0.1 # Multiplier for wall-repulsion force. ++ ++ # Ideal radius for a 5x5 grid is 0.1, so ideal separation is 0.2 ++ repulsion_threshold = 0.2 ++ boundary_margin = 0.1 ++ ++ for _ in range(n_iters): ++ forces = np.zeros_like(centers) ++ ++ # a. Calculate circle-circle repulsion forces. ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ ++ # If circles are closer than the threshold, they repel. ++ if 0 < dist < repulsion_threshold: ++ # Force is stronger for closer circles, directed along the vector between them. ++ force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # b. Calculate boundary repulsion forces to keep circles inside. ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) ++ ++ # c. Update center positions based on the calculated forces. ++ centers += step_size * forces ++ ++ # d. Clip centers as a safety measure to ensure they stay within the square. ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ # 3. Compute maximum valid radii for the final, relaxed configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. +- # This preserves the relative size of the two circles. + sum_r = radii[i] + radii[j] +- scale = dist / sum_r +- +- radii[i] *= scale +- radii[j] *= scale ++ if sum_r > 1e-12: # Avoid division by zero ++ scale = dist / sum_r ++ radii[i] *= scale ++ radii[j] *= scale ++ else: # If both radii are already ~0, ensure they are exactly 0 ++ radii[i] = 0 ++ radii[j] = 0 ++ + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/main.py new file mode 100644 index 0000000000000000000000000000000000000000..bd2d6295d75de72529c8c7f9492ab77f639f28a3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/main.py @@ -0,0 +1,135 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using iterative relaxation""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by starting with a + grid layout and then iteratively relaxing the positions of the centers + based on repulsive forces. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a strong initial configuration: a 5x5 grid (optimal for 25) + # and place the 26th circle in an interstitial void. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + centers[25] = [0.4, 0.4] + + # 2. Iteratively relax the circle positions using a physics-based model. + # This allows the circles to push each other into a more efficient packing. + n_iters = 80 # Number of relaxation steps. + step_size = 0.002 # How much to move centers per step (learning rate). + repulsion_strength = 0.02 # Multiplier for circle-circle repulsion force. + boundary_strength = 0.1 # Multiplier for wall-repulsion force. + + # Ideal radius for a 5x5 grid is 0.1, so ideal separation is 0.2 + repulsion_threshold = 0.2 + boundary_margin = 0.1 + + for _ in range(n_iters): + forces = np.zeros_like(centers) + + # a. Calculate circle-circle repulsion forces. + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + + # If circles are closer than the threshold, they repel. + if 0 < dist < repulsion_threshold: + # Force is stronger for closer circles, directed along the vector between them. + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # b. Calculate boundary repulsion forces to keep circles inside. + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + # c. Update center positions based on the calculated forces. + centers += step_size * forces + + # d. Clip centers as a safety measure to ensure they stay within the square. + centers = np.clip(centers, 0.0, 1.0) + + # 3. Compute maximum valid radii for the final, relaxed configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/original.py new file mode 100644 index 0000000000000000000000000000000000000000..936546557a6a6b3d8340b4aceeaef87b5c6df0f8 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/original.py @@ -0,0 +1,96 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by building on the + optimal packing for 25 circles and placing the 26th in an interstitial void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Place 25 circles in a 5x5 grid. This is the optimal packing for 25 + # equal circles, providing a strong, high-density baseline. The ideal radius + # for each circle in this packing is 0.1. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a central interstitial void. + # The grid points are at {0.1, 0.3, 0.5, 0.7, 0.9}. The voids are at + # {0.2, 0.4, 0.6, 0.8}. We choose (0.4, 0.4) as it is one of the + # most central voids, creating a symmetric disruption. + centers[25] = [0.4, 0.4] + + # 3. Compute maximum valid radii for this configuration using an iterative + # and robust calculation method. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + # This preserves the relative size of the two circles. + sum_r = radii[i] + radii[j] + scale = dist / sum_r + + radii[i] *= scale + radii[j] *= scale + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..60365199a95d314b2c4934bfaf7a4cf092f21c7c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_24/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_24/results +Run 1/1 completed in 0.09 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9228512816016508 + 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.2991, 0.2991)\n centers[7] = (0.5009, 0.2991)\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.2991, 0.5009)\n centers[12] = (0.5009, 0.5009)\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.4000, 0.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9228512816016508} + visualization_path: + execution_time_mean: 0.08643895573914051 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..8e9d64ac708fed9ffda338541166b09bc9a58056 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9228512816016508, + "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.2991, 0.2991)\n centers[7] = (0.5009, 0.2991)\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.2991, 0.5009)\n centers[12] = (0.5009, 0.5009)\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.4000, 0.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9228512816016508 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_24/results/packing_viz.png", + "execution_time_mean": 0.08643895573914051, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c630723cdc5bc37d5ea58c4a22f7642803e2145 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_24/rewrite.txt @@ -0,0 +1,126 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using iterative relaxation""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by starting with a + grid layout and then iteratively relaxing the positions of the centers + based on repulsive forces. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a strong initial configuration: a 5x5 grid (optimal for 25) + # and place the 26th circle in an interstitial void. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + centers[25] = [0.4, 0.4] + + # 2. Iteratively relax the circle positions using a physics-based model. + # This allows the circles to push each other into a more efficient packing. + n_iters = 80 # Number of relaxation steps. + step_size = 0.002 # How much to move centers per step (learning rate). + repulsion_strength = 0.02 # Multiplier for circle-circle repulsion force. + boundary_strength = 0.1 # Multiplier for wall-repulsion force. + + # Ideal radius for a 5x5 grid is 0.1, so ideal separation is 0.2 + repulsion_threshold = 0.2 + boundary_margin = 0.1 + + for _ in range(n_iters): + forces = np.zeros_like(centers) + + # a. Calculate circle-circle repulsion forces. + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + + # If circles are closer than the threshold, they repel. + if 0 < dist < repulsion_threshold: + # Force is stronger for closer circles, directed along the vector between them. + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # b. Calculate boundary repulsion forces to keep circles inside. + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + # c. Update center positions based on the calculated forces. + centers += step_size * forces + + # d. Clip centers as a safety measure to ensure they stay within the square. + centers = np.clip(centers, 0.0, 1.0) + + # 3. Compute maximum valid radii for the final, relaxed configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..440cad97ea9a6b2f6b0198865b9617aefd22056e Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..db71c0076ab0a728d6f694518dffabce966d6339 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_25/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_25/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9200929312704162 + 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.4000, 0.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9200929312704162} + visualization_path: + execution_time_mean: 0.0041770050302147865 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..4cdd2faf7ce9b85dfc9b02f73e92935e425f89c9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9200929312704162, + "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.4000, 0.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9200929312704162 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_25/results/packing_viz.png", + "execution_time_mean": 0.0041770050302147865, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8c3e0f846d0358ec9c1eb566f7e3bbc66dfb5d65 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..2574270bd7c2ece08131fa7ce888a7708e050649 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/edit.diff @@ -0,0 +1,148 @@ +--- a/original.py ++++ b/original.py +@@ -1,102 +1,122 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + ++ This method starts with a 5x5 grid (optimal for 25 circles), ++ deforms it by creating a void using a Gaussian repulsive force, ++ and then places the 26th circle into that new, larger void. ++ + Returns: +- Tuple of (centers, radii, sum_of_radii) ++ Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle +- sum_of_radii: Sum of all radii + """ +- # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + +- # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), +- # which provides a very strong and dense foundation. +- # The 26th circle is then placed in a central interstitial void. ++ # 1. Start with a 5x5 grid, the basis for N=25 packing. ++ x_coords = np.linspace(0.1, 0.9, 5) ++ y_coords = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords, y_coords) ++ grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 1. Place 25 circles in a 5x5 grid. +- # This is the known optimal packing for 25 equal circles. +- x_coords_5 = np.linspace(0.1, 0.9, 5) +- y_coords_5 = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords_5, y_coords_5) +- centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T ++ # 2. Define an interstitial void center. ++ # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. ++ void_center = np.array([0.4, 0.4]) + +- # 2. Place the 26th circle in a promising interstitial position. +- # The voids in a 5x5 grid are at positions like (0.2, 0.2), (0.2, 0.4), etc. +- # Placing it at (0.4, 0.4) puts it in a central void, surrounded by +- # circles at (0.1, 0.1), (0.3, 0.1), (0.1, 0.3), and (0.3, 0.3). +- # Placing the circle in a corner void may be less disruptive to the overall +- # packing as it primarily affects already-constrained edge circles. +- centers[25] = [0.2, 0.2] ++ # 3. Deform the grid by "pushing" points away from the void center ++ # using a Gaussian repulsive model. This creates space for the 26th circle. ++ amplitude = 0.04 # Magnitude of the push. ++ sigma = 0.15 # Spatial extent of the push. + +- # Compute maximum valid radii for this configuration ++ # Calculate displacement vectors from the void center to each grid point ++ displacements = grid_centers - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ ++ # Avoid division by zero for any point at the void center ++ mask = distances > 1e-9 ++ ++ # Calculate push magnitude based on Gaussian function ++ push_magnitudes = np.zeros(25) ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ ++ # Normalize displacement vectors and apply the push ++ displacements[mask] /= distances[mask, np.newaxis] ++ deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] ++ ++ # Ensure centers remain within the unit square after deformation. ++ deformed_centers = np.clip(deformed_centers, 0.0, 1.0) ++ ++ centers[:25] = deformed_centers ++ ++ # 4. Place the 26th circle in the center of the created void. ++ centers[25] = void_center ++ ++ # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders +- for i in range(n): +- x, y = centers[i] +- radii[i] = min(x, y, 1 - x, 1 - y) ++ radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) ++ + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/main.py new file mode 100644 index 0000000000000000000000000000000000000000..0b2d1f78a6fc241a0d1ec516363eb647ad763426 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/main.py @@ -0,0 +1,122 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid (optimal for 25 circles), + deforms it by creating a void using a Gaussian repulsive force, + and then places the 26th circle into that new, larger void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an interstitial void center. + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the grid by "pushing" points away from the void center + # using a Gaussian repulsive model. This creates space for the 26th circle. + amplitude = 0.04 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # Ensure centers remain within the unit square after deformation. + deformed_centers = np.clip(deformed_centers, 0.0, 1.0) + + centers[:25] = deformed_centers + + # 4. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/original.py new file mode 100644 index 0000000000000000000000000000000000000000..225e352e60a295c9ed99ff3b055cf6bee64371d9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/original.py @@ -0,0 +1,102 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a promising interstitial position. + # The voids in a 5x5 grid are at positions like (0.2, 0.2), (0.2, 0.4), etc. + # Placing it at (0.4, 0.4) puts it in a central void, surrounded by + # circles at (0.1, 0.1), (0.3, 0.1), (0.1, 0.3), and (0.3, 0.3). + # Placing the circle in a corner void may be less disruptive to the overall + # packing as it primarily affects already-constrained edge circles. + centers[25] = [0.2, 0.2] + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..c74115d7ace8d8acb86a1cda27593d2b2d7a988b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_28/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_28/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9617474245900182 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0959)\n centers[2] = (0.5014, 0.0959)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0959, 0.2986)\n centers[6] = (0.2819, 0.2819)\n centers[7] = (0.5181, 0.2819)\n centers[8] = (0.7041, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0959, 0.5014)\n centers[11] = (0.2819, 0.5181)\n centers[12] = (0.5181, 0.5181)\n centers[13] = (0.7041, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7041)\n centers[17] = (0.5014, 0.7041)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9617474245900182} + visualization_path: + execution_time_mean: 0.0042416248470544815 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..9b62db5bc43b605ec7eac4b38d42cfb70213f428 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9617474245900182, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0959)\n centers[2] = (0.5014, 0.0959)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0959, 0.2986)\n centers[6] = (0.2819, 0.2819)\n centers[7] = (0.5181, 0.2819)\n centers[8] = (0.7041, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0959, 0.5014)\n centers[11] = (0.2819, 0.5181)\n centers[12] = (0.5181, 0.5181)\n centers[13] = (0.7041, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7041)\n centers[17] = (0.5014, 0.7041)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9617474245900182 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_28/results/packing_viz.png", + "execution_time_mean": 0.0042416248470544815, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..916ee13235b92993a9afbd74d77513702327694a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_28/rewrite.txt @@ -0,0 +1,113 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid (optimal for 25 circles), + deforms it by creating a void using a Gaussian repulsive force, + and then places the 26th circle into that new, larger void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an interstitial void center. + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the grid by "pushing" points away from the void center + # using a Gaussian repulsive model. This creates space for the 26th circle. + amplitude = 0.04 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # Ensure centers remain within the unit square after deformation. + deformed_centers = np.clip(deformed_centers, 0.0, 1.0) + + centers[:25] = deformed_centers + + # 4. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9bacf8a72c1242ff4f89f9b674c5d74c41d9753a Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..deda4244cb74d8f36d6184f245dd6fa10bb71a70 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/edit.diff @@ -0,0 +1,137 @@ +--- a/original.py ++++ b/original.py +@@ -1,102 +1,126 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Place the 26th circle in a promising interstitial position. +- # The voids in a 5x5 grid are at positions like (0.2, 0.2), (0.2, 0.4), etc. +- # Placing it at (0.4, 0.4) puts it in a central void, surrounded by +- # circles at (0.1, 0.1), (0.3, 0.1), (0.1, 0.3), and (0.3, 0.3). +- # Placing the circle in a corner void may be less disruptive to the overall +- # packing as it primarily affects already-constrained edge circles. +- centers[25] = [0.2, 0.2] ++ # 2. Deform the grid with a Gaussian repulsion to create a central void. ++ # This method, inspired by a successful prior program, pushes circles ++ # away from a central point to make space for the 26th circle. This ++ # allows for a more global and efficient rearrangement of the packing. ++ void_center = np.array([0.4, 0.4]) ++ amplitude = 0.042 # Tuned displacement magnitude ++ sigma = 0.15 # Range of the repulsive force + +- # Compute maximum valid radii for this configuration ++ grid_centers = centers[:25].copy() ++ ++ # Calculate displacement vectors from the void center to each grid point ++ displacements = grid_centers - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ ++ # Avoid division by zero for any point at the void center ++ mask = distances > 1e-9 ++ ++ # Calculate push magnitude based on Gaussian function ++ push_magnitudes = np.zeros(25) ++ if np.any(mask): ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ ++ # Normalize displacement vectors and apply the push ++ displacements[mask] /= distances[mask, np.newaxis] ++ centers[:25] = grid_centers + displacements * push_magnitudes[:, np.newaxis] ++ ++ # 3. Place the 26th circle in the center of the created void. ++ centers[25] = void_center ++ ++ # Safeguard: clip centers to stay within the unit square. ++ centers = np.clip(centers, 0.0001, 0.9999) ++ ++ # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/main.py new file mode 100644 index 0000000000000000000000000000000000000000..c6cb8006b0ac625a7315d0a2cf4159eb339533ea --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/main.py @@ -0,0 +1,126 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a Gaussian repulsion to create a central void. + # This method, inspired by a successful prior program, pushes circles + # away from a central point to make space for the 26th circle. This + # allows for a more global and efficient rearrangement of the packing. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 # Tuned displacement magnitude + sigma = 0.15 # Range of the repulsive force + + grid_centers = centers[:25].copy() + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + centers[:25] = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Safeguard: clip centers to stay within the unit square. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/original.py new file mode 100644 index 0000000000000000000000000000000000000000..225e352e60a295c9ed99ff3b055cf6bee64371d9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/original.py @@ -0,0 +1,102 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a promising interstitial position. + # The voids in a 5x5 grid are at positions like (0.2, 0.2), (0.2, 0.4), etc. + # Placing it at (0.4, 0.4) puts it in a central void, surrounded by + # circles at (0.1, 0.1), (0.3, 0.1), (0.1, 0.3), and (0.3, 0.3). + # Placing the circle in a corner void may be less disruptive to the overall + # packing as it primarily affects already-constrained edge circles. + centers[25] = [0.2, 0.2] + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..69d72070259ff6db5ec0773cfda08c1cd88cf7bd --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_29/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_29/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.963260393808555 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2810, 0.2810)\n centers[7] = (0.5190, 0.2810)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2810, 0.5190)\n centers[12] = (0.5190, 0.5190)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.963260393808555} + visualization_path: + execution_time_mean: 0.0026159430854022503 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..79c1b4bc4f9cc188cb1fbbce27d2fd88b8855001 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.963260393808555, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2810, 0.2810)\n centers[7] = (0.5190, 0.2810)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2810, 0.5190)\n centers[12] = (0.5190, 0.5190)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.963260393808555 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_29/results/packing_viz.png", + "execution_time_mean": 0.0026159430854022503, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..e99a755e71358e5ece9e4f39911caf845e1ac046 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_29/search_replace.txt @@ -0,0 +1,59 @@ + +reintroduce_gaussian_deformation + + +The current approach of placing the 26th circle in a rigid 5x5 grid is suboptimal, as it only locally perturbs the packing and creates small circles. The visualization clearly shows this inefficiency in the bottom-left corner, where four circles are shrunk to accommodate a new, also small, circle. A previously successful strategy involved deforming the entire grid using a Gaussian repulsion force to create a central void. This allows for a more global and efficient rearrangement. + +I am re-introducing this superior method, using the central void at (0.4, 0.4) which affects the packing more symmetrically. I've also slightly increased the repulsion `amplitude` from the previously successful value of 0.04 to 0.042, in an attempt to create a slightly larger void for the 26th circle and further improve the total sum of radii. This change directly addresses the inefficient pattern observed in the visualization. + + +<<<<<<< SEARCH + # 2. Place the 26th circle in a promising interstitial position. + # The voids in a 5x5 grid are at positions like (0.2, 0.2), (0.2, 0.4), etc. + # Placing it at (0.4, 0.4) puts it in a central void, surrounded by + # circles at (0.1, 0.1), (0.3, 0.1), (0.1, 0.3), and (0.3, 0.3). + # Placing the circle in a corner void may be less disruptive to the overall + # packing as it primarily affects already-constrained edge circles. + centers[25] = [0.2, 0.2] + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii +======= + # 2. Deform the grid with a Gaussian repulsion to create a central void. + # This method, inspired by a successful prior program, pushes circles + # away from a central point to make space for the 26th circle. This + # allows for a more global and efficient rearrangement of the packing. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 # Tuned displacement magnitude + sigma = 0.15 # Range of the repulsive force + + grid_centers = centers[:25].copy() + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + centers[:25] = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Safeguard: clip centers to stay within the unit square. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e76eacc650d41f08a6c9a74e9ce62560b443e856 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..d714d4146c3d453f8d6ddd542ff684b60b1309f3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/edit.diff @@ -0,0 +1,237 @@ +--- a/original.py ++++ b/original.py +@@ -1,91 +1,176 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" +- + import numpy as np + +- +-def construct_packing(): +- """ +- Construct a specific arrangement of 26 circles in a unit square +- that attempts to maximize the sum of their radii. +- +- This new arrangement uses a 5x5 grid, which is the optimal packing for 25 +- equal circles. This provides a very strong structural base. +- +- Returns: +- Tuple of (centers, radii) +- centers: np.array of shape (26, 2) with (x, y) coordinates +- radii: np.array of shape (26) with radius of each circle +- """ +- # Initialize arrays for 26 circles +- n = 26 +- centers = np.zeros((n, 2)) +- +- # Place 25 circles in a 5x5 grid. This is the optimal packing for 25 +- # equal circles, providing a strong baseline. The radius for each +- # circle in this ideal packing is 0.1, for a sum of 2.5. +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T +- +- # Place the 26th circle. As a simple approach, we place it at the +- # center (0.5, 0.5), which intentionally overlaps with the center circle +- # of the 5x5 grid. The radius calculation will correctly handle this +- # by shrinking both conflicting radii to zero, effectively yielding a +- # 24-circle packing with a sum of radii of 2.4. This configuration is +- # a massive improvement over the initial concentric pattern. +- centers[25] = [0.5, 0.5] +- +- # Compute maximum valid radii for this configuration +- radii = compute_max_radii(centers) +- return centers, radii +- ++# A small epsilon for floating point comparisons to avoid issues with exact equality or near-zero values. ++EPSILON = 1e-9 + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. ++ ++ This version iteratively refines radii to better resolve overlaps. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] +- radii = np.ones(n) +- +- # First, limit by distance to square borders ++ ++ # 1. Initialize radii based on boundary constraints ++ radii = np.zeros(n) + for i in range(n): + x, y = centers[i] +- # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) +- +- # Then, limit by distance to other circles +- # Each pair of circles with centers at distance d can have +- # sum of radii at most d to avoid overlap ++ radii[i] = max(radii[i], EPSILON) # Ensure a small positive radius ++ ++ # 2. Iteratively resolve overlaps with other circles ++ # This loop ensures that all circles eventually satisfy the non-overlap constraint. ++ # A fixed number of iterations (e.g., 200) allows for changes to propagate. ++ # The choice of 200 is a heuristic for N=26; more iterations may provide higher precision ++ # but also increase computation time. ++ ++ for _ in range(200): # Max iterations for radius convergence ++ changed_in_pass = False ++ for i in range(n): ++ for j in range(i + 1, n): ++ dist = np.linalg.norm(centers[i] - centers[j]) ++ ++ # Check for overlap, allowing for minor floating point inaccuracies ++ if radii[i] + radii[j] > dist - EPSILON: ++ # Overlap detected. Scale down both radii proportionally ++ # to make their sum equal to the distance between centers. ++ ++ sum_current_radii = radii[i] + radii[j] ++ ++ if sum_current_radii > EPSILON: # Avoid division by zero ++ # Calculate new radii such that r_i' + r_j' = dist ++ # and r_i' / r_j' = r_i / r_j ++ scale_factor = dist / sum_current_radii ++ ++ new_r_i = radii[i] * scale_factor ++ new_r_j = radii[j] * scale_factor ++ ++ # Only update if there's an actual significant reduction ++ if new_r_i < radii[i] - EPSILON or new_r_j < radii[j] - EPSILON: ++ radii[i] = new_r_i ++ radii[j] = new_r_j ++ changed_in_pass = True ++ if not changed_in_pass: ++ break # No significant changes in this pass, so converged ++ ++ # Final clamping to ensure radii are non-negative and don't exceed boundary limits + for i in range(n): +- for j in range(i + 1, n): +- dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) +- +- # If current radii would cause overlap +- if radii[i] + radii[j] > dist: +- # Scale both radii proportionally +- scale = dist / (radii[i] + radii[j]) +- radii[i] *= scale +- radii[j] *= scale +- ++ x, y = centers[i] ++ boundary_r = min(x, y, 1 - x, 1 - y) ++ radii[i] = max(0.0, min(radii[i], boundary_r)) # Ensure non-negative and within boundary ++ + return radii + + ++def construct_packing(): ++ """ ++ Construct an arrangement of 26 circles in a unit square using Simulated Annealing ++ to maximize the sum of their radii. ++ ++ Returns: ++ Tuple of (centers, radii) ++ centers: np.array of shape (26, 2) with (x, y) coordinates ++ radii: np.array of shape (26) with radius of each circle ++ """ ++ n = 26 ++ ++ # Simulated Annealing parameters ++ initial_temp = 0.1 # Starting temperature, tuned for unit square coordinates and small step sizes ++ cooling_rate = 0.9999 # Slower cooling for better exploration of the solution space ++ min_temp = 1e-6 # Minimum temperature to stop the annealing process ++ max_iterations = 500000 # Total iterations for the annealing process ++ ++ # 1. Initial State: Jittered grid for a reasonably good starting point ++ # This helps SA to start from a more organized configuration rather than pure randomness. ++ grid_side = int(np.ceil(np.sqrt(n))) # e.g., for n=26, grid_side=6 ++ ++ # Create an initial grid of points, enough to hold n circles ++ # Spreading points from 0.1 to 0.9 provides some initial space from the boundaries. ++ initial_grid_x = np.linspace(0.1, 0.9, grid_side) ++ initial_grid_y = np.linspace(0.1, 0.9, grid_side) ++ ++ xx, yy = np.meshgrid(initial_grid_x, initial_grid_y) ++ grid_points = np.vstack([xx.ravel(), yy.ravel()]).T ++ ++ # Take the first n points and add a small random jitter to break perfect symmetry ++ current_centers = grid_points[:n] + (np.random.rand(n, 2) - 0.5) * 0.05 ++ ++ # Ensure centers are within valid bounds (e.g., 0 to 1) ++ current_centers = np.clip(current_centers, EPSILON, 1.0 - EPSILON) ++ ++ # Calculate initial score (sum of radii) ++ current_radii = compute_max_radii(current_centers) ++ current_score = np.sum(current_radii) ++ ++ best_centers = np.copy(current_centers) ++ best_radii = np.copy(current_radii) ++ best_score = current_score ++ ++ temp = initial_temp ++ ++ for iteration in range(max_iterations): ++ if temp < min_temp: ++ break # Stop if temperature drops below minimum ++ ++ # Perturbation: Create a new candidate state by randomly moving one circle ++ new_centers = np.copy(current_centers) ++ circle_idx = np.random.randint(n) ++ ++ # Move the selected circle by a small random step ++ # Step size decreases with temperature, allowing for finer adjustments later in the search. ++ step_magnitude = 0.05 * temp # Scaling factor for step size ++ new_centers[circle_idx] += (np.random.rand(2) - 0.5) * step_magnitude ++ ++ # Ensure the new center stays within the unit square boundaries ++ new_centers[circle_idx] = np.clip(new_centers[circle_idx], EPSILON, 1.0 - EPSILON) ++ ++ # Calculate the score for the new configuration ++ new_radii = compute_max_radii(new_centers) ++ new_score = np.sum(new_radii) ++ ++ # Simulated Annealing acceptance criterion ++ # If the new solution is better, always accept it. ++ # If it's worse, accept it with a probability that depends on how much worse it is ++ # and the current temperature. ++ if new_score > current_score: ++ current_centers = np.copy(new_centers) ++ current_radii = np.copy(new_radii) ++ current_score = new_score ++ ++ # Update the best-found solution if the current one is better ++ if current_score > best_score: ++ best_centers = np.copy(current_centers) ++ best_radii = np.copy(current_radii) ++ best_score = current_score ++ else: ++ # Accept worse solutions with a probability to escape local minima ++ delta_score = new_score - current_score # This will be negative ++ acceptance_prob = np.exp(delta_score / temp) ++ ++ if np.random.rand() < acceptance_prob: ++ current_centers = np.copy(new_centers) ++ current_radii = np.copy(new_radii) ++ current_score = new_score ++ ++ # Cooling schedule: exponential decay ++ temp *= cooling_rate ++ ++ return best_centers, best_radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/main.py new file mode 100644 index 0000000000000000000000000000000000000000..bf70abe579ce2003e933f313e0d57cbcb25d4827 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/main.py @@ -0,0 +1,176 @@ +# EVOLVE-BLOCK-START +import numpy as np + +# A small epsilon for floating point comparisons to avoid issues with exact equality or near-zero values. +EPSILON = 1e-9 + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + This version iteratively refines radii to better resolve overlaps. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # 1. Initialize radii based on boundary constraints + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + radii[i] = max(radii[i], EPSILON) # Ensure a small positive radius + + # 2. Iteratively resolve overlaps with other circles + # This loop ensures that all circles eventually satisfy the non-overlap constraint. + # A fixed number of iterations (e.g., 200) allows for changes to propagate. + # The choice of 200 is a heuristic for N=26; more iterations may provide higher precision + # but also increase computation time. + + for _ in range(200): # Max iterations for radius convergence + changed_in_pass = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # Check for overlap, allowing for minor floating point inaccuracies + if radii[i] + radii[j] > dist - EPSILON: + # Overlap detected. Scale down both radii proportionally + # to make their sum equal to the distance between centers. + + sum_current_radii = radii[i] + radii[j] + + if sum_current_radii > EPSILON: # Avoid division by zero + # Calculate new radii such that r_i' + r_j' = dist + # and r_i' / r_j' = r_i / r_j + scale_factor = dist / sum_current_radii + + new_r_i = radii[i] * scale_factor + new_r_j = radii[j] * scale_factor + + # Only update if there's an actual significant reduction + if new_r_i < radii[i] - EPSILON or new_r_j < radii[j] - EPSILON: + radii[i] = new_r_i + radii[j] = new_r_j + changed_in_pass = True + if not changed_in_pass: + break # No significant changes in this pass, so converged + + # Final clamping to ensure radii are non-negative and don't exceed boundary limits + for i in range(n): + x, y = centers[i] + boundary_r = min(x, y, 1 - x, 1 - y) + radii[i] = max(0.0, min(radii[i], boundary_r)) # Ensure non-negative and within boundary + + return radii + + +def construct_packing(): + """ + Construct an arrangement of 26 circles in a unit square using Simulated Annealing + to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + + # Simulated Annealing parameters + initial_temp = 0.1 # Starting temperature, tuned for unit square coordinates and small step sizes + cooling_rate = 0.9999 # Slower cooling for better exploration of the solution space + min_temp = 1e-6 # Minimum temperature to stop the annealing process + max_iterations = 500000 # Total iterations for the annealing process + + # 1. Initial State: Jittered grid for a reasonably good starting point + # This helps SA to start from a more organized configuration rather than pure randomness. + grid_side = int(np.ceil(np.sqrt(n))) # e.g., for n=26, grid_side=6 + + # Create an initial grid of points, enough to hold n circles + # Spreading points from 0.1 to 0.9 provides some initial space from the boundaries. + initial_grid_x = np.linspace(0.1, 0.9, grid_side) + initial_grid_y = np.linspace(0.1, 0.9, grid_side) + + xx, yy = np.meshgrid(initial_grid_x, initial_grid_y) + grid_points = np.vstack([xx.ravel(), yy.ravel()]).T + + # Take the first n points and add a small random jitter to break perfect symmetry + current_centers = grid_points[:n] + (np.random.rand(n, 2) - 0.5) * 0.05 + + # Ensure centers are within valid bounds (e.g., 0 to 1) + current_centers = np.clip(current_centers, EPSILON, 1.0 - EPSILON) + + # Calculate initial score (sum of radii) + current_radii = compute_max_radii(current_centers) + current_score = np.sum(current_radii) + + best_centers = np.copy(current_centers) + best_radii = np.copy(current_radii) + best_score = current_score + + temp = initial_temp + + for iteration in range(max_iterations): + if temp < min_temp: + break # Stop if temperature drops below minimum + + # Perturbation: Create a new candidate state by randomly moving one circle + new_centers = np.copy(current_centers) + circle_idx = np.random.randint(n) + + # Move the selected circle by a small random step + # Step size decreases with temperature, allowing for finer adjustments later in the search. + step_magnitude = 0.05 * temp # Scaling factor for step size + new_centers[circle_idx] += (np.random.rand(2) - 0.5) * step_magnitude + + # Ensure the new center stays within the unit square boundaries + new_centers[circle_idx] = np.clip(new_centers[circle_idx], EPSILON, 1.0 - EPSILON) + + # Calculate the score for the new configuration + new_radii = compute_max_radii(new_centers) + new_score = np.sum(new_radii) + + # Simulated Annealing acceptance criterion + # If the new solution is better, always accept it. + # If it's worse, accept it with a probability that depends on how much worse it is + # and the current temperature. + if new_score > current_score: + current_centers = np.copy(new_centers) + current_radii = np.copy(new_radii) + current_score = new_score + + # Update the best-found solution if the current one is better + if current_score > best_score: + best_centers = np.copy(current_centers) + best_radii = np.copy(current_radii) + best_score = current_score + else: + # Accept worse solutions with a probability to escape local minima + delta_score = new_score - current_score # This will be negative + acceptance_prob = np.exp(delta_score / temp) + + if np.random.rand() < acceptance_prob: + current_centers = np.copy(new_centers) + current_radii = np.copy(new_radii) + current_score = new_score + + # Cooling schedule: exponential decay + temp *= cooling_rate + + return best_centers, best_radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/original.py new file mode 100644 index 0000000000000000000000000000000000000000..41cc63a12c7d775596366a4232be31830d06e18e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/original.py @@ -0,0 +1,91 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This new arrangement uses a 5x5 grid, which is the optimal packing for 25 + equal circles. This provides a very strong structural base. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Place 25 circles in a 5x5 grid. This is the optimal packing for 25 + # equal circles, providing a strong baseline. The radius for each + # circle in this ideal packing is 0.1, for a sum of 2.5. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # Place the 26th circle. As a simple approach, we place it at the + # center (0.5, 0.5), which intentionally overlaps with the center circle + # of the 5x5 grid. The radius calculation will correctly handle this + # by shrinking both conflicting radii to zero, effectively yielding a + # 24-circle packing with a sum of radii of 2.4. This configuration is + # a massive improvement over the initial concentric pattern. + centers[25] = [0.5, 0.5] + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..3b4e17cf34032c0fb91d94ea4effa60b543c0a86 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_3/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_3/results +Run 1/1 completed in 247.42 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.3104432519787574 + public: {'centers_str': ' centers[0] = (0.1091, 0.1097)\n centers[1] = (0.2602, 0.0956)\n centers[2] = (0.4079, 0.1037)\n centers[3] = (0.5287, 0.1065)\n centers[4] = (0.7021, 0.0712)\n centers[5] = (0.8874, 0.0914)\n centers[6] = (0.0522, 0.2526)\n centers[7] = (0.2203, 0.2279)\n centers[8] = (0.3997, 0.3328)\n centers[9] = (0.5804, 0.2638)\n centers[10] = (0.6956, 0.2691)\n centers[11] = (0.9389, 0.2470)\n centers[12] = (0.1511, 0.4368)\n centers[13] = (0.2871, 0.4298)\n centers[14] = (0.4753, 0.3848)\n centers[15] = (0.5740, 0.4337)\n centers[16] = (0.7272, 0.4307)\n centers[17] = (0.9010, 0.4328)\n centers[18] = (0.0473, 0.6108)\n centers[19] = (0.2485, 0.5672)\n centers[20] = (0.4036, 0.5450)\n centers[21] = (0.5882, 0.5900)\n centers[22] = (0.7496, 0.5827)\n centers[23] = (0.9442, 0.5698)\n centers[24] = (0.0555, 0.7247)\n centers[25] = (0.2743, 0.7480)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.3104432519787574} + visualization_path: + execution_time_mean: 247.42427778802812 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..7a7a19e64bfd4159431d1e90ace34a0744bb5968 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.3104432519787574, + "public": { + "centers_str": " centers[0] = (0.1091, 0.1097)\n centers[1] = (0.2602, 0.0956)\n centers[2] = (0.4079, 0.1037)\n centers[3] = (0.5287, 0.1065)\n centers[4] = (0.7021, 0.0712)\n centers[5] = (0.8874, 0.0914)\n centers[6] = (0.0522, 0.2526)\n centers[7] = (0.2203, 0.2279)\n centers[8] = (0.3997, 0.3328)\n centers[9] = (0.5804, 0.2638)\n centers[10] = (0.6956, 0.2691)\n centers[11] = (0.9389, 0.2470)\n centers[12] = (0.1511, 0.4368)\n centers[13] = (0.2871, 0.4298)\n centers[14] = (0.4753, 0.3848)\n centers[15] = (0.5740, 0.4337)\n centers[16] = (0.7272, 0.4307)\n centers[17] = (0.9010, 0.4328)\n centers[18] = (0.0473, 0.6108)\n centers[19] = (0.2485, 0.5672)\n centers[20] = (0.4036, 0.5450)\n centers[21] = (0.5882, 0.5900)\n centers[22] = (0.7496, 0.5827)\n centers[23] = (0.9442, 0.5698)\n centers[24] = (0.0555, 0.7247)\n centers[25] = (0.2743, 0.7480)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.3104432519787574 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_3/results/packing_viz.png", + "execution_time_mean": 247.42427778802812, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b1cbdc7cf8437fc8ccbc914311c1b7c2fc3b7ad Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..eb19271e4bd53c1cc39a75893901a814428e7c1d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/edit.diff @@ -0,0 +1,140 @@ +--- a/original.py ++++ b/original.py +@@ -1,122 +1,124 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid (optimal for 25 circles), + deforms it by creating a void using a Gaussian repulsive force, + and then places the 26th circle into that new, larger void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an interstitial void center. + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the grid by "pushing" points away from the void center + # using a Gaussian repulsive model. This creates space for the 26th circle. +- amplitude = 0.04 # Magnitude of the push. +- sigma = 0.15 # Spatial extent of the push. ++ # Reduced amplitude based on visual feedback: the central circle was too dominant, ++ # and its neighbors were too small. A smaller push might allow for a more balanced ++ # distribution and a higher total sum of radii. ++ amplitude = 0.03 # Reduced displacement magnitude from 0.04/0.042 ++ sigma = 0.15 # Spatial extent of the push (kept same) + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] + +- # Ensure centers remain within the unit square after deformation. +- deformed_centers = np.clip(deformed_centers, 0.0, 1.0) +- + centers[:25] = deformed_centers + + # 4. Place the 26th circle in the center of the created void. + centers[25] = void_center ++ ++ # Ensure all centers remain strictly within the unit square boundaries. ++ # Using 0.0001 and 0.9999 ensures a minimal radius is possible for boundary circles. ++ centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + +- # First, limit by distance to square borders ++ # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + +- + # Iteratively limit by distance to other circles, allowing constraints to propagate +- for _ in range(300): # Iterate to ensure convergence ++ # This loop count (300) ensures sufficient convergence for typical packing problems. ++ for _ in range(300): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] +- if sum_r > 1e-9: # Avoid division by zero for coincident centers ++ if sum_r > 1e-9: # Avoid division by zero for nearly coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + +- # Check for significant change to set the flag ++ # Check for significant change to set the flag, improving loop termination + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: +- break # Exit early if the configuration is stable ++ break # Exit early if the configuration is stable, saving computation + + return radii +- +- + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/main.py new file mode 100644 index 0000000000000000000000000000000000000000..66d2511994642eca0e072d9f1f08ce6ad938432c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/main.py @@ -0,0 +1,124 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid (optimal for 25 circles), + deforms it by creating a void using a Gaussian repulsive force, + and then places the 26th circle into that new, larger void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an interstitial void center. + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the grid by "pushing" points away from the void center + # using a Gaussian repulsive model. This creates space for the 26th circle. + # Reduced amplitude based on visual feedback: the central circle was too dominant, + # and its neighbors were too small. A smaller push might allow for a more balanced + # distribution and a higher total sum of radii. + amplitude = 0.03 # Reduced displacement magnitude from 0.04/0.042 + sigma = 0.15 # Spatial extent of the push (kept same) + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + centers[:25] = deformed_centers + + # 4. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Ensure all centers remain strictly within the unit square boundaries. + # Using 0.0001 and 0.9999 ensures a minimal radius is possible for boundary circles. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + # This loop count (300) ensures sufficient convergence for typical packing problems. + for _ in range(300): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for nearly coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag, improving loop termination + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable, saving computation + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/original.py new file mode 100644 index 0000000000000000000000000000000000000000..0b2d1f78a6fc241a0d1ec516363eb647ad763426 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/original.py @@ -0,0 +1,122 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid (optimal for 25 circles), + deforms it by creating a void using a Gaussian repulsive force, + and then places the 26th circle into that new, larger void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an interstitial void center. + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the grid by "pushing" points away from the void center + # using a Gaussian repulsive model. This creates space for the 26th circle. + amplitude = 0.04 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # Ensure centers remain within the unit square after deformation. + deformed_centers = np.clip(deformed_centers, 0.0, 1.0) + + centers[:25] = deformed_centers + + # 4. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..4ca97c5ac9a893aded0c4bbfdacb9a76ff9f5fb7 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_31/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_31/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9527651153447374 + public: {'centers_str': ' centers[0] = (0.0996, 0.0996)\n centers[1] = (0.2990, 0.0969)\n centers[2] = (0.5010, 0.0969)\n centers[3] = (0.7004, 0.0996)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0969, 0.2990)\n centers[6] = (0.2864, 0.2864)\n centers[7] = (0.5136, 0.2864)\n centers[8] = (0.7031, 0.2990)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0969, 0.5010)\n centers[11] = (0.2864, 0.5136)\n centers[12] = (0.5136, 0.5136)\n centers[13] = (0.7031, 0.5010)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0996, 0.7004)\n centers[16] = (0.2990, 0.7031)\n centers[17] = (0.5010, 0.7031)\n centers[18] = (0.7004, 0.7004)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9527651153447374} + visualization_path: + execution_time_mean: 0.0026168241165578365 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..ca94e20dd1541a4a0a562bedfc0cdff01040a7b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9527651153447374, + "public": { + "centers_str": " centers[0] = (0.0996, 0.0996)\n centers[1] = (0.2990, 0.0969)\n centers[2] = (0.5010, 0.0969)\n centers[3] = (0.7004, 0.0996)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0969, 0.2990)\n centers[6] = (0.2864, 0.2864)\n centers[7] = (0.5136, 0.2864)\n centers[8] = (0.7031, 0.2990)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0969, 0.5010)\n centers[11] = (0.2864, 0.5136)\n centers[12] = (0.5136, 0.5136)\n centers[13] = (0.7031, 0.5010)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0996, 0.7004)\n centers[16] = (0.2990, 0.7031)\n centers[17] = (0.5010, 0.7031)\n centers[18] = (0.7004, 0.7004)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9527651153447374 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_31/results/packing_viz.png", + "execution_time_mean": 0.0026168241165578365, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ac0b357a3899e6aaf5b67804569b63d0c9a79ef --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_31/rewrite.txt @@ -0,0 +1,114 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid (optimal for 25 circles), + deforms it by creating a void using a Gaussian repulsive force, + and then places the 26th circle into that new, larger void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an interstitial void center. + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the grid by "pushing" points away from the void center + # using a Gaussian repulsive model. This creates space for the 26th circle. + # Reduced amplitude based on visual feedback: the central circle was too dominant, + # and its neighbors were too small. A smaller push might allow for a more balanced + # distribution and a higher total sum of radii. + amplitude = 0.03 # Reduced displacement magnitude from 0.04/0.042 + sigma = 0.15 # Spatial extent of the push (kept same) + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + centers[:25] = deformed_centers + + # 4. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Ensure all centers remain strictly within the unit square boundaries. + # Using 0.0001 and 0.9999 ensures a minimal radius is possible for boundary circles. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + # This loop count (300) ensures sufficient convergence for typical packing problems. + for _ in range(300): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for nearly coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag, improving loop termination + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable, saving computation + + return radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..124b38ce0c7696b526e033e0ffbb28e3d6671e80 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..085c4a2e4abee3a40c3ce58e8d17ecf8b3a9c858 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_32/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_32/results +Run 1/1 completed in 0.24 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9635652269686839 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9635652269686839} + visualization_path: + execution_time_mean: 0.23898031236603856 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..7f0d5f5f20f4f47e090a4dccc98a86aa236fca51 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9635652269686839, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9635652269686839 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_32/results/packing_viz.png", + "execution_time_mean": 0.23898031236603856, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..327562254329dafe8b791211228b74112de143f6 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..2ca1776fd4da909d8ecb9e4be61f1c9f75c71af9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_33/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_33/results +Run 1/1 completed in 0.16 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9633528546569237 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0955)\n centers[2] = (0.5014, 0.0955)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0955, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7045, 0.2986)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0955, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7045, 0.5014)\n centers[14] = (0.9002, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7045)\n centers[17] = (0.5014, 0.7045)\n centers[18] = (0.7005, 0.7005)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1000, 0.9000)\n centers[21] = (0.3000, 0.9002)\n centers[22] = (0.5000, 0.9002)\n centers[23] = (0.7000, 0.9000)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9633528546569237} + visualization_path: + execution_time_mean: 0.1600528508424759 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..d7ac3d23b8cca9c82753aac6c1ea5665271263d3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9633528546569237, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0955)\n centers[2] = (0.5014, 0.0955)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0955, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7045, 0.2986)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0955, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7045, 0.5014)\n centers[14] = (0.9002, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7045)\n centers[17] = (0.5014, 0.7045)\n centers[18] = (0.7005, 0.7005)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1000, 0.9000)\n centers[21] = (0.3000, 0.9002)\n centers[22] = (0.5000, 0.9002)\n centers[23] = (0.7000, 0.9000)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9633528546569237 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_33/results/packing_viz.png", + "execution_time_mean": 0.1600528508424759, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0c507b873a99fd45190f451669e25abcc9d52ea Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..492a4699f694f26a9090b978244cd4044d07423a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/edit.diff @@ -0,0 +1,242 @@ +--- a/original.py ++++ b/original.py +@@ -1,135 +1,190 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles using iterative relaxation""" ++"""Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles by starting with a +- grid layout and then iteratively relaxing the positions of the centers +- based on repulsive forces. ++ Constructs a high-density arrangement of 26 circles by initially placing ++ them in a deformed grid and then iteratively refining their positions ++ using a two-stage adaptive force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + +- # 1. Start with a strong initial configuration: a 5x5 grid (optimal for 25) +- # and place the 26th circle in an interstitial void. ++ # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) +- centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T +- centers[25] = [0.4, 0.4] ++ base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Iteratively relax the circle positions using a physics-based model. +- # This allows the circles to push each other into a more efficient packing. +- n_iters = 80 # Number of relaxation steps. +- step_size = 0.002 # How much to move centers per step (learning rate). +- repulsion_strength = 0.02 # Multiplier for circle-circle repulsion force. +- boundary_strength = 0.1 # Multiplier for wall-repulsion force. +- +- # Ideal radius for a 5x5 grid is 0.1, so ideal separation is 0.2 +- repulsion_threshold = 0.2 +- boundary_margin = 0.1 ++ # 2. Place the 26th circle in a central interstitial void (0.4, 0.4). ++ # This is a common and effective starting point for the extra circle. ++ void_center = np.array([0.4, 0.4]) + +- for _ in range(n_iters): ++ # 3. Apply a Gaussian deformation to the 25 grid circles. ++ # This "pre-pushes" them away from the void center, making initial room. ++ deformed_centers_25 = np.copy(base_centers_25) ++ ++ # Tuned hyperparameters for the Gaussian push based on prior successful runs: ++ amplitude = 0.042 # Amplitude for more initial separation ++ sigma = 0.15 # Spread of the Gaussian, defines influence range ++ ++ for i in range(25): ++ pos_vector = base_centers_25[i] - void_center ++ dist_sq = np.sum(pos_vector**2) ++ ++ push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) ++ ++ if np.linalg.norm(pos_vector) > 1e-9: ++ direction = pos_vector / np.linalg.norm(pos_vector) ++ displacement = direction * push_magnitude ++ deformed_centers_25[i] += displacement ++ ++ # Combine deformed 25 circles with the 26th. ++ centers[:25] = deformed_centers_25 ++ centers[25] = void_center ++ centers = np.clip(centers, 0.0, 1.0) # Ensure centers remain within bounds ++ ++ # 4. Two-Stage Adaptive Force-Directed Relaxation. ++ # This improves upon simple iterative refinement by using different ++ # force parameters for exploration (global adjustment) and refinement (fine-tuning). ++ ++ # Shared parameters for both stages: ++ repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) ++ boundary_margin = 0.04 # How close circles can get to boundary before repulsion ++ ++ # Stage 1: Exploration - Broad adjustment and global distribution ++ # Aims to rapidly resolve initial overlaps and broadly distribute circles. ++ exploration_iters = 100 ++ exploration_step_size = 0.0025 ++ exploration_repulsion_strength = 0.015 ++ exploration_boundary_strength = 0.075 ++ ++ for _ in range(exploration_iters): + forces = np.zeros_like(centers) + +- # a. Calculate circle-circle repulsion forces. ++ # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- +- # If circles are closer than the threshold, they repel. + if 0 < dist < repulsion_threshold: +- # Force is stronger for closer circles, directed along the vector between them. +- force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist ++ force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + +- # b. Calculate boundary repulsion forces to keep circles inside. ++ # Boundary repulsion + for i in range(n): + x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) +- +- # c. Update center positions based on the calculated forces. +- centers += step_size * forces ++ if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + +- # d. Clip centers as a safety measure to ensure they stay within the square. ++ centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + +- # 3. Compute maximum valid radii for the final, relaxed configuration. ++ # Stage 2: Refinement - Fine-tuning and precise adjustments ++ # Uses smaller movements to converge to a better local optimum. ++ refinement_iters = 150 ++ refinement_step_size = 0.0008 # Much smaller step size ++ refinement_repulsion_strength = 0.005 # Weaker repulsion ++ refinement_boundary_strength = 0.025 # Weaker boundary repulsion ++ ++ for _ in range(refinement_iters): ++ forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers += refinement_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ # 5. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. +- for _ in range(500): +- changed_in_pass = False ++ for _ in range(300): ++ changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + +- # If they overlap (with a small tolerance for floating point math) +- if radii[i] + radii[j] > dist + 1e-12: +- # Scale both radii down proportionally to resolve the overlap. ++ # If they overlap ++ if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] +- if sum_r > 1e-12: # Avoid division by zero ++ if sum_r > 1e-9: # Avoid division by zero ++ # Scale both radii proportionally to resolve the overlap. + scale = dist / sum_r +- radii[i] *= scale +- radii[j] *= scale +- else: # If both radii are already ~0, ensure they are exactly 0 +- radii[i] = 0 +- radii[j] = 0 ++ ri_new = radii[i] * scale ++ rj_new = radii[j] * scale + +- changed_in_pass = True ++ # Check for significant change to set the flag and update ++ if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: ++ radii[i] = ri_new ++ radii[j] = rj_new ++ changes_made = True + + # If a full pass resulted in no changes, the packing is stable. +- if not changed_in_pass: ++ if not changes_made: + break + + return radii +- +- + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/main.py new file mode 100644 index 0000000000000000000000000000000000000000..b36be4226dd1e5b3a9b71c00ec6a59d9934d5aaa --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/main.py @@ -0,0 +1,190 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by initially placing + them in a deformed grid and then iteratively refining their positions + using a two-stage adaptive force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a central interstitial void (0.4, 0.4). + # This is a common and effective starting point for the extra circle. + void_center = np.array([0.4, 0.4]) + + # 3. Apply a Gaussian deformation to the 25 grid circles. + # This "pre-pushes" them away from the void center, making initial room. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push based on prior successful runs: + amplitude = 0.042 # Amplitude for more initial separation + sigma = 0.15 # Spread of the Gaussian, defines influence range + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) # Ensure centers remain within bounds + + # 4. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) + boundary_margin = 0.04 # How close circles can get to boundary before repulsion + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(300): + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero + # Scale both radii proportionally to resolve the overlap. + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag and update + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/original.py new file mode 100644 index 0000000000000000000000000000000000000000..bd2d6295d75de72529c8c7f9492ab77f639f28a3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/original.py @@ -0,0 +1,135 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using iterative relaxation""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by starting with a + grid layout and then iteratively relaxing the positions of the centers + based on repulsive forces. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a strong initial configuration: a 5x5 grid (optimal for 25) + # and place the 26th circle in an interstitial void. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + centers[25] = [0.4, 0.4] + + # 2. Iteratively relax the circle positions using a physics-based model. + # This allows the circles to push each other into a more efficient packing. + n_iters = 80 # Number of relaxation steps. + step_size = 0.002 # How much to move centers per step (learning rate). + repulsion_strength = 0.02 # Multiplier for circle-circle repulsion force. + boundary_strength = 0.1 # Multiplier for wall-repulsion force. + + # Ideal radius for a 5x5 grid is 0.1, so ideal separation is 0.2 + repulsion_threshold = 0.2 + boundary_margin = 0.1 + + for _ in range(n_iters): + forces = np.zeros_like(centers) + + # a. Calculate circle-circle repulsion forces. + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + + # If circles are closer than the threshold, they repel. + if 0 < dist < repulsion_threshold: + # Force is stronger for closer circles, directed along the vector between them. + force_magnitude = repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # b. Calculate boundary repulsion forces to keep circles inside. + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + # c. Update center positions based on the calculated forces. + centers += step_size * forces + + # d. Clip centers as a safety measure to ensure they stay within the square. + centers = np.clip(centers, 0.0, 1.0) + + # 3. Compute maximum valid radii for the final, relaxed configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..5541f13ba42272f33d465a3215f8624bb68536fd --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_35/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_35/results +Run 1/1 completed in 0.29 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9635652269686839 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9635652269686839} + visualization_path: + execution_time_mean: 0.28896150179207325 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..96d8ddec2b884677f86babed50431cd3c68f7827 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9635652269686839, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9635652269686839 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_35/results/packing_viz.png", + "execution_time_mean": 0.28896150179207325, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..0eab42426ee10d7465b7ecac8a5b7b0f1b82752e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_35/rewrite.txt @@ -0,0 +1,181 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by initially placing + them in a deformed grid and then iteratively refining their positions + using a two-stage adaptive force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a central interstitial void (0.4, 0.4). + # This is a common and effective starting point for the extra circle. + void_center = np.array([0.4, 0.4]) + + # 3. Apply a Gaussian deformation to the 25 grid circles. + # This "pre-pushes" them away from the void center, making initial room. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push based on prior successful runs: + amplitude = 0.042 # Amplitude for more initial separation + sigma = 0.15 # Spread of the Gaussian, defines influence range + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) # Ensure centers remain within bounds + + # 4. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) + boundary_margin = 0.04 # How close circles can get to boundary before repulsion + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(300): + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero + # Scale both radii proportionally to resolve the overlap. + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag and update + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37e628b1042f739a03136a1f680373705dcb06b8 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..229d3925f1056aec641452c1741b47edd1c5a63b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/edit.diff @@ -0,0 +1,226 @@ +--- a/original.py ++++ b/original.py +@@ -1,160 +1,182 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ +- Construct a specific arrangement of 26 circles in a unit square +- that attempts to maximize the sum of their radii. ++ Constructs a high-density arrangement of 26 circles by initially placing ++ them in a deformed grid and then iteratively refining their positions ++ using a two-stage adaptive force-directed relaxation. + + Returns: +- Tuple of (centers, radii, sum_of_radii) ++ Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle +- sum_of_radii: Sum of all radii + """ +- # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. +- # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. +- # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) +- ++ + # Hyperparameters for the Gaussian push: +- amplitude = 0.042 # The maximum distance to push a circle. Increased slightly to make more room. ++ amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) +- +- # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) +- +- # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center ++ centers = np.clip(centers, 0.0, 1.0) # Ensure centers remain within bounds + +- # Clip centers to ensure they stay within the square, although the push is gentle. +- centers = np.clip(centers, 0.0, 1.0) ++ # 5. Two-Stage Adaptive Force-Directed Relaxation. ++ # This improves upon simple refinement by using different parameters for ++ # global exploration and local fine-tuning. + +- # 5. Iteratively refine positions for all 26 circles after the initial deformation. +- # This allows all circles, including the 26th, to find more optimal positions +- # through mutual repulsion and boundary interactions. +- refinement_iters = 80 # Number of refinement steps. Increased for more thorough relaxation. +- refinement_step_size = 0.002 # Step size for center adjustments. +- refinement_repulsion_strength = 0.02 # Multiplier for circle-circle repulsion force. +- refinement_boundary_strength = 0.1 # Multiplier for wall-repulsion force. +- refinement_repulsion_threshold = 0.2 # Threshold distance for repulsion to start (e.g., 2*r_ideal for 0.1 circles) +- refinement_boundary_margin = 0.1 # Distance from boundary where repulsion starts. ++ # Shared parameters for both stages: ++ repulsion_threshold = 0.185 # Encourages tight packing. ++ boundary_margin = 0.04 # Smaller margin for better edge utilization. + +- for _ in range(refinement_iters): ++ # Stage 1: Exploration - Broad adjustments and global distribution. ++ exploration_iters = 100 ++ exploration_step_size = 0.0025 ++ exploration_repulsion_strength = 0.015 ++ exploration_boundary_strength = 0.075 ++ ++ for _ in range(exploration_iters): + forces = np.zeros_like(centers) +- +- # a. Calculate circle-circle repulsion forces. ++ ++ # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- +- if 0 < dist < refinement_repulsion_threshold: +- force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + +- # b. Calculate boundary repulsion forces. ++ # Boundary repulsion + for i in range(n): + x, y = centers[i] +- if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) +- if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) +- if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) +- if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) +- +- # c. Update center positions. +- centers += refinement_step_size * forces +- +- # d. Clip centers. ++ if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + +- # 6. Compute maximum valid radii for the refined configuration. ++ # Stage 2: Refinement - Fine-tuning and precise adjustments. ++ refinement_iters = 150 ++ refinement_step_size = 0.0008 # Much smaller step size ++ refinement_repulsion_strength = 0.005 # Weaker repulsion ++ refinement_boundary_strength = 0.025 # Weaker boundary repulsion ++ ++ for _ in range(refinement_iters): ++ forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers += refinement_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/main.py new file mode 100644 index 0000000000000000000000000000000000000000..cbbc508dc619c9f584bb06a057ade768d9e7728b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/main.py @@ -0,0 +1,182 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by initially placing + them in a deformed grid and then iteratively refining their positions + using a two-stage adaptive force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) # Ensure centers remain within bounds + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple refinement by using different parameters for + # global exploration and local fine-tuning. + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing. + boundary_margin = 0.04 # Smaller margin for better edge utilization. + + # Stage 1: Exploration - Broad adjustments and global distribution. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/original.py new file mode 100644 index 0000000000000000000000000000000000000000..8758155929c84916648ad978650354bd4090fe2f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/original.py @@ -0,0 +1,160 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. Increased slightly to make more room. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Iteratively refine positions for all 26 circles after the initial deformation. + # This allows all circles, including the 26th, to find more optimal positions + # through mutual repulsion and boundary interactions. + refinement_iters = 80 # Number of refinement steps. Increased for more thorough relaxation. + refinement_step_size = 0.002 # Step size for center adjustments. + refinement_repulsion_strength = 0.02 # Multiplier for circle-circle repulsion force. + refinement_boundary_strength = 0.1 # Multiplier for wall-repulsion force. + refinement_repulsion_threshold = 0.2 # Threshold distance for repulsion to start (e.g., 2*r_ideal for 0.1 circles) + refinement_boundary_margin = 0.1 # Distance from boundary where repulsion starts. + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # a. Calculate circle-circle repulsion forces. + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # b. Calculate boundary repulsion forces. + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + # c. Update center positions. + centers += refinement_step_size * forces + + # d. Clip centers. + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..d6ae52086c4955f6d1ccd767c4dd6a49328aac66 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_36/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_36/results +Run 1/1 completed in 0.36 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9635652269686839 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9635652269686839} + visualization_path: + execution_time_mean: 0.360147959087044 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..e98ab49923807591d2b6899154414eeceb4594e1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9635652269686839, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9635652269686839 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_36/results/packing_viz.png", + "execution_time_mean": 0.360147959087044, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..aadd802d8b71296f40ec4b5fd92c10a53a326b6d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_36/rewrite.txt @@ -0,0 +1,173 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by initially placing + them in a deformed grid and then iteratively refining their positions + using a two-stage adaptive force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) # Ensure centers remain within bounds + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple refinement by using different parameters for + # global exploration and local fine-tuning. + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing. + boundary_margin = 0.04 # Smaller margin for better edge utilization. + + # Stage 1: Exploration - Broad adjustments and global distribution. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37b11d43e66204070f0e5c5e9a8c9b4955febf75 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..6bdaf8397c8ceaa291c6366f9c29e1ccb0cb8f65 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/edit.diff @@ -0,0 +1,279 @@ +--- a/original.py ++++ b/original.py +@@ -1,190 +1,181 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" ++"""Constructor-based circle packing for n=26 circles using Potential Field Annealing""" + + import numpy as np + + + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles by initially placing +- them in a deformed grid and then iteratively refining their positions +- using a two-stage adaptive force-directed relaxation. ++ Constructs a high-density arrangement of 26 circles using a novel ++ "Potential Field Annealing" algorithm. It starts with a deformed grid, ++ then uses a simulated annealing process where forces are guided by a ++ "potential" field estimated from neighbor distances. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + +- # 1. Initial Grid for 25 circles: Start with a 5x5 grid. ++ # 1. Initial Grid for 25 circles (proven good starting point). + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Place the 26th circle in a central interstitial void (0.4, 0.4). +- # This is a common and effective starting point for the extra circle. ++ # 2. Place 26th circle in a central void and apply Gaussian deformation. + void_center = np.array([0.4, 0.4]) ++ amplitude = 0.042 ++ sigma = 0.15 + +- # 3. Apply a Gaussian deformation to the 25 grid circles. +- # This "pre-pushes" them away from the void center, making initial room. + deformed_centers_25 = np.copy(base_centers_25) +- +- # Tuned hyperparameters for the Gaussian push based on prior successful runs: +- amplitude = 0.042 # Amplitude for more initial separation +- sigma = 0.15 # Spread of the Gaussian, defines influence range +- + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) +- + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) +- + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) +- displacement = direction * push_magnitude +- deformed_centers_25[i] += displacement ++ deformed_centers_25[i] += direction * push_magnitude + +- # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center +- centers = np.clip(centers, 0.0, 1.0) # Ensure centers remain within bounds ++ centers = np.clip(centers, 0.0, 1.0) + +- # 4. Two-Stage Adaptive Force-Directed Relaxation. +- # This improves upon simple iterative refinement by using different +- # force parameters for exploration (global adjustment) and refinement (fine-tuning). ++ # 3. Potential Field Annealing Loop. ++ annealing_iters = 500 ++ k_neighbors = 4 # Number of neighbors to consider for potential calculation ++ ++ # Force model parameters ++ attraction_k = 0.05 ++ repulsion_k = 0.0001 ++ ++ # Annealing schedule parameters ++ step_size = 0.2 ++ initial_temp = 0.008 ++ # Exponential cooling schedule ++ cooling_rate = np.exp(np.log(1e-4) / annealing_iters) ++ temperature = initial_temp + +- # Shared parameters for both stages: +- repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) +- boundary_margin = 0.04 # How close circles can get to boundary before repulsion ++ # Boundary repulsion parameters ++ boundary_strength = 0.1 ++ boundary_margin = 0.05 + +- # Stage 1: Exploration - Broad adjustment and global distribution +- # Aims to rapidly resolve initial overlaps and broadly distribute circles. +- exploration_iters = 100 +- exploration_step_size = 0.0025 +- exploration_repulsion_strength = 0.015 +- exploration_boundary_strength = 0.075 ++ # Pre-calculate distances matrix for efficiency ++ distances = np.zeros((n, n)) + +- for _ in range(exploration_iters): ++ for iter_num in range(annealing_iters): ++ # A. Estimate "potential" for each circle's position. ++ # Proxy for potential: average distance to k-nearest neighbors. ++ potentials = np.zeros(n) ++ for i in range(n): ++ for j in range(n): ++ distances[i, j] = np.linalg.norm(centers[i] - centers[j]) ++ # Get distances to other circles, sort, and find avg of k-nearest ++ neighbor_dist = np.sort(distances[i, np.arange(n) != i]) ++ potentials[i] = np.mean(neighbor_dist[:k_neighbors]) ++ ++ # B. Calculate forces based on potential and repulsion. + forces = np.zeros_like(centers) +- +- # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist +- force_vec = force_magnitude * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec ++ dist = distances[i, j] ++ if dist < 1e-9: continue ++ ++ vec = centers[j] - centers[i] ++ direction = vec / dist + +- # Boundary repulsion ++ # Repulsive force (prevents collapse, inverse square) ++ repulsive_force = -repulsion_k / (dist**2) ++ ++ # Attractive force (pulls towards high-potential areas) ++ # Force on i is proportional to potential of j, and vice versa. ++ attractive_force_on_i = attraction_k * potentials[j] ++ attractive_force_on_j = attraction_k * potentials[i] ++ ++ force_on_i = (repulsive_force + attractive_force_on_i) * direction ++ force_on_j = (repulsive_force + attractive_force_on_j) * -direction ++ ++ forces[i] += force_on_i ++ forces[j] += force_on_j ++ ++ # C. Add boundary repulsion. + for i in range(n): + x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) ++ if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) ++ ++ # D. Update positions with forces and random thermal movement. ++ random_moves = (np.random.rand(n, 2) - 0.5) * 2 * temperature ++ centers += forces * step_size + random_moves ++ centers = np.clip(centers, 0.0, 1.0) + +- centers += exploration_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) ++ # E. Cool down the temperature. ++ temperature *= cooling_rate + +- # Stage 2: Refinement - Fine-tuning and precise adjustments +- # Uses smaller movements to converge to a better local optimum. +- refinement_iters = 150 +- refinement_step_size = 0.0008 # Much smaller step size +- refinement_repulsion_strength = 0.005 # Weaker repulsion +- refinement_boundary_strength = 0.025 # Weaker boundary repulsion +- +- for _ in range(refinement_iters): +- forces = np.zeros_like(centers) +- +- # Circle-circle repulsion +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist +- force_vec = force_magnitude * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- +- # Boundary repulsion +- for i in range(n): +- x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) +- +- centers += refinement_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- +- # 5. Compute maximum valid radii for the final, refined configuration. ++ # 4. Final radius calculation on the settled configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. +- for _ in range(300): ++ for _ in range(500): # Increased iterations for better convergence + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap +- if radii[i] + radii[j] > dist: ++ if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] +- if sum_r > 1e-9: # Avoid division by zero +- # Scale both radii proportionally to resolve the overlap. +- scale = dist / sum_r +- ri_new = radii[i] * scale +- rj_new = radii[j] * scale +- +- # Check for significant change to set the flag and update +- if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: +- radii[i] = ri_new +- radii[j] = rj_new +- changes_made = True ++ # Scale both radii proportionally to resolve the overlap. ++ scale = dist / sum_r ++ ri_new = radii[i] * scale ++ rj_new = radii[j] * scale ++ ++ # Check for significant change to set the flag and update ++ if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: ++ radii[i] = ri_new ++ radii[j] = rj_new ++ changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/main.py new file mode 100644 index 0000000000000000000000000000000000000000..c5ec6eadb55e5edaacefcf002bbe1bf764c398e1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/main.py @@ -0,0 +1,181 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using Potential Field Annealing""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a novel + "Potential Field Annealing" algorithm. It starts with a deformed grid, + then uses a simulated annealing process where forces are guided by a + "potential" field estimated from neighbor distances. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles (proven good starting point). + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place 26th circle in a central void and apply Gaussian deformation. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 + sigma = 0.15 + + deformed_centers_25 = np.copy(base_centers_25) + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + deformed_centers_25[i] += direction * push_magnitude + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 3. Potential Field Annealing Loop. + annealing_iters = 500 + k_neighbors = 4 # Number of neighbors to consider for potential calculation + + # Force model parameters + attraction_k = 0.05 + repulsion_k = 0.0001 + + # Annealing schedule parameters + step_size = 0.2 + initial_temp = 0.008 + # Exponential cooling schedule + cooling_rate = np.exp(np.log(1e-4) / annealing_iters) + temperature = initial_temp + + # Boundary repulsion parameters + boundary_strength = 0.1 + boundary_margin = 0.05 + + # Pre-calculate distances matrix for efficiency + distances = np.zeros((n, n)) + + for iter_num in range(annealing_iters): + # A. Estimate "potential" for each circle's position. + # Proxy for potential: average distance to k-nearest neighbors. + potentials = np.zeros(n) + for i in range(n): + for j in range(n): + distances[i, j] = np.linalg.norm(centers[i] - centers[j]) + # Get distances to other circles, sort, and find avg of k-nearest + neighbor_dist = np.sort(distances[i, np.arange(n) != i]) + potentials[i] = np.mean(neighbor_dist[:k_neighbors]) + + # B. Calculate forces based on potential and repulsion. + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + dist = distances[i, j] + if dist < 1e-9: continue + + vec = centers[j] - centers[i] + direction = vec / dist + + # Repulsive force (prevents collapse, inverse square) + repulsive_force = -repulsion_k / (dist**2) + + # Attractive force (pulls towards high-potential areas) + # Force on i is proportional to potential of j, and vice versa. + attractive_force_on_i = attraction_k * potentials[j] + attractive_force_on_j = attraction_k * potentials[i] + + force_on_i = (repulsive_force + attractive_force_on_i) * direction + force_on_j = (repulsive_force + attractive_force_on_j) * -direction + + forces[i] += force_on_i + forces[j] += force_on_j + + # C. Add boundary repulsion. + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + # D. Update positions with forces and random thermal movement. + random_moves = (np.random.rand(n, 2) - 0.5) * 2 * temperature + centers += forces * step_size + random_moves + centers = np.clip(centers, 0.0, 1.0) + + # E. Cool down the temperature. + temperature *= cooling_rate + + # 4. Final radius calculation on the settled configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for better convergence + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + # Scale both radii proportionally to resolve the overlap. + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag and update + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/original.py new file mode 100644 index 0000000000000000000000000000000000000000..b36be4226dd1e5b3a9b71c00ec6a59d9934d5aaa --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/original.py @@ -0,0 +1,190 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by initially placing + them in a deformed grid and then iteratively refining their positions + using a two-stage adaptive force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a central interstitial void (0.4, 0.4). + # This is a common and effective starting point for the extra circle. + void_center = np.array([0.4, 0.4]) + + # 3. Apply a Gaussian deformation to the 25 grid circles. + # This "pre-pushes" them away from the void center, making initial room. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push based on prior successful runs: + amplitude = 0.042 # Amplitude for more initial separation + sigma = 0.15 # Spread of the Gaussian, defines influence range + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) # Ensure centers remain within bounds + + # 4. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) + boundary_margin = 0.04 # How close circles can get to boundary before repulsion + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(300): + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero + # Scale both radii proportionally to resolve the overlap. + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag and update + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..4053cc397417b9e83067ce18d40f9e7149cdb2ec --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_37/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_37/results +Run 1/1 completed in 2.25 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 0.4527296287705159 + public: {'centers_str': ' centers[0] = (0.3729, 0.3658)\n centers[1] = (0.4480, 0.3337)\n centers[2] = (0.5284, 0.3209)\n centers[3] = (0.5496, 0.3879)\n centers[4] = (0.6211, 0.3681)\n centers[5] = (0.3350, 0.4399)\n centers[6] = (0.4192, 0.4181)\n centers[7] = (0.4832, 0.3994)\n centers[8] = (0.5292, 0.4569)\n centers[9] = (0.5965, 0.4417)\n centers[10] = (0.3229, 0.5216)\n centers[11] = (0.3968, 0.4822)\n centers[12] = (0.5199, 0.5215)\n centers[13] = (0.5894, 0.5083)\n centers[14] = (0.6657, 0.4546)\n centers[15] = (0.3914, 0.5488)\n centers[16] = (0.4568, 0.5384)\n centers[17] = (0.5007, 0.5936)\n centers[18] = (0.5664, 0.5725)\n centers[19] = (0.6567, 0.5352)\n centers[20] = (0.3581, 0.6141)\n centers[21] = (0.4313, 0.6125)\n centers[22] = (0.4732, 0.6697)\n centers[23] = (0.5535, 0.6514)\n centers[24] = (0.6265, 0.6091)\n centers[25] = (0.4655, 0.4718)', 'num_circles': 26} + private: {'reported_sum_of_radii': 0.4527296287705159} + visualization_path: + execution_time_mean: 2.2538893441669643 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..c288db5a97f5fdfd3c030e9cdd22d6ad22d8244b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 0.4527296287705159, + "public": { + "centers_str": " centers[0] = (0.3729, 0.3658)\n centers[1] = (0.4480, 0.3337)\n centers[2] = (0.5284, 0.3209)\n centers[3] = (0.5496, 0.3879)\n centers[4] = (0.6211, 0.3681)\n centers[5] = (0.3350, 0.4399)\n centers[6] = (0.4192, 0.4181)\n centers[7] = (0.4832, 0.3994)\n centers[8] = (0.5292, 0.4569)\n centers[9] = (0.5965, 0.4417)\n centers[10] = (0.3229, 0.5216)\n centers[11] = (0.3968, 0.4822)\n centers[12] = (0.5199, 0.5215)\n centers[13] = (0.5894, 0.5083)\n centers[14] = (0.6657, 0.4546)\n centers[15] = (0.3914, 0.5488)\n centers[16] = (0.4568, 0.5384)\n centers[17] = (0.5007, 0.5936)\n centers[18] = (0.5664, 0.5725)\n centers[19] = (0.6567, 0.5352)\n centers[20] = (0.3581, 0.6141)\n centers[21] = (0.4313, 0.6125)\n centers[22] = (0.4732, 0.6697)\n centers[23] = (0.5535, 0.6514)\n centers[24] = (0.6265, 0.6091)\n centers[25] = (0.4655, 0.4718)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 0.4527296287705159 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_37/results/packing_viz.png", + "execution_time_mean": 2.2538893441669643, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..40dea0d2bbe3e844ea4a87df97ac08cd5b0c57a1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_37/rewrite.txt @@ -0,0 +1,172 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using Potential Field Annealing""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a novel + "Potential Field Annealing" algorithm. It starts with a deformed grid, + then uses a simulated annealing process where forces are guided by a + "potential" field estimated from neighbor distances. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles (proven good starting point). + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place 26th circle in a central void and apply Gaussian deformation. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 + sigma = 0.15 + + deformed_centers_25 = np.copy(base_centers_25) + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + deformed_centers_25[i] += direction * push_magnitude + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 3. Potential Field Annealing Loop. + annealing_iters = 500 + k_neighbors = 4 # Number of neighbors to consider for potential calculation + + # Force model parameters + attraction_k = 0.05 + repulsion_k = 0.0001 + + # Annealing schedule parameters + step_size = 0.2 + initial_temp = 0.008 + # Exponential cooling schedule + cooling_rate = np.exp(np.log(1e-4) / annealing_iters) + temperature = initial_temp + + # Boundary repulsion parameters + boundary_strength = 0.1 + boundary_margin = 0.05 + + # Pre-calculate distances matrix for efficiency + distances = np.zeros((n, n)) + + for iter_num in range(annealing_iters): + # A. Estimate "potential" for each circle's position. + # Proxy for potential: average distance to k-nearest neighbors. + potentials = np.zeros(n) + for i in range(n): + for j in range(n): + distances[i, j] = np.linalg.norm(centers[i] - centers[j]) + # Get distances to other circles, sort, and find avg of k-nearest + neighbor_dist = np.sort(distances[i, np.arange(n) != i]) + potentials[i] = np.mean(neighbor_dist[:k_neighbors]) + + # B. Calculate forces based on potential and repulsion. + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + dist = distances[i, j] + if dist < 1e-9: continue + + vec = centers[j] - centers[i] + direction = vec / dist + + # Repulsive force (prevents collapse, inverse square) + repulsive_force = -repulsion_k / (dist**2) + + # Attractive force (pulls towards high-potential areas) + # Force on i is proportional to potential of j, and vice versa. + attractive_force_on_i = attraction_k * potentials[j] + attractive_force_on_j = attraction_k * potentials[i] + + force_on_i = (repulsive_force + attractive_force_on_i) * direction + force_on_j = (repulsive_force + attractive_force_on_j) * -direction + + forces[i] += force_on_i + forces[j] += force_on_j + + # C. Add boundary repulsion. + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= boundary_strength * (y - (1 - boundary_margin)) + + # D. Update positions with forces and random thermal movement. + random_moves = (np.random.rand(n, 2) - 0.5) * 2 * temperature + centers += forces * step_size + random_moves + centers = np.clip(centers, 0.0, 1.0) + + # E. Cool down the temperature. + temperature *= cooling_rate + + # 4. Final radius calculation on the settled configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): # Increased iterations for better convergence + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + # Scale both radii proportionally to resolve the overlap. + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag and update + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3cc9792618f3676570ece0d87145300c4a210761 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..57f1bab7c44b93d4ea0d2616a2fc7b0c435823ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/edit.diff @@ -0,0 +1,276 @@ +--- a/original.py ++++ b/original.py +@@ -1,122 +1,204 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + +-def construct_packing(): +- """ +- Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid +- to create a larger void for the 26th circle. +- +- Returns: +- Tuple of (centers, radii) +- centers: np.array of shape (26, 2) with (x, y) coordinates +- radii: np.array of shape (26) with radius of each circle +- """ +- n = 26 +- centers = np.zeros((n, 2)) +- +- # 1. Start with the 25 centers of a 5x5 grid. +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T +- +- # 2. Define the center of the void where the 26th circle will be placed. +- # A central interstitial void at (0.4, 0.4) is a good candidate. +- void_center = np.array([0.4, 0.4]) +- +- # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. +- # This pushes nearby circles away to make more room. +- deformed_centers_25 = np.copy(base_centers_25) +- +- # Hyperparameters for the Gaussian push: +- amplitude = 0.04 # The maximum distance to push a circle. +- sigma = 0.15 # The "spread" of the push, controlling its influence range. +- +- for i in range(25): +- pos_vector = base_centers_25[i] - void_center +- dist_sq = np.sum(pos_vector**2) +- +- # Gaussian function defines the push magnitude based on distance from the void center. +- push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) +- +- # The push is directed radially away from the void center. +- if np.linalg.norm(pos_vector) > 1e-9: +- direction = pos_vector / np.linalg.norm(pos_vector) +- displacement = direction * push_magnitude +- deformed_centers_25[i] += displacement +- +- # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. +- centers[:25] = deformed_centers_25 +- centers[25] = void_center +- +- # Clip centers to ensure they stay within the square, although the push is gentle. +- centers = np.clip(centers, 0.0, 1.0) +- +- # 5. Compute maximum valid radii for the new configuration. +- radii = compute_max_radii(centers) +- return centers, radii +- ++# A small epsilon for floating point comparisons to avoid issues with exact equality or near-zero values. ++EPSILON = 1e-12 # Using a smaller epsilon for higher precision in radius calculations and general robustness + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] +- ++ + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) ++ radii[i] = max(radii[i], EPSILON) # Ensure a small positive radius to prevent division by zero later + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. +- for _ in range(500): ++ # The proportional scaling mechanism is efficient in reducing overlaps. ++ for _ in range(500): # Fixed number of iterations for robustness (from Inspiration 4) + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) +- ++ + # If they overlap (with a small tolerance for floating point math) +- if radii[i] + radii[j] > dist + 1e-12: ++ # Using EPSILON here for precision (from Inspiration 4) ++ if radii[i] + radii[j] > dist + EPSILON: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] +- if sum_r > 1e-12: # Avoid division by zero +- scale = dist / sum_r ++ ++ # Avoid division by zero if radii are extremely small (from Inspiration 4) ++ if sum_r < EPSILON: ++ radii[i] = 0.0 # Set to zero if they are effectively non-existent ++ radii[j] = 0.0 ++ changed_in_pass = True # Mark as changed to continue iterations ++ continue ++ ++ scale = dist / sum_r ++ ++ # Apply scaling. Only mark as changed if actual reduction happens (from Inspiration 4) ++ if scale < 1.0 - EPSILON: # Check for a meaningful reduction + radii[i] *= scale + radii[j] *= scale +- else: # If both radii are already ~0, ensure they are exactly 0 +- radii[i] = 0 +- radii[j] = 0 +- +- changed_in_pass = True +- +- # If a full pass resulted in no changes, the packing is stable. ++ changed_in_pass = True ++ ++ # If a full pass resulted in no significant changes, the packing is stable. + if not changed_in_pass: + break +- ++ ++ # Final check to ensure radii are non-negative and respect boundary limits (from Inspiration 4) ++ for i in range(n): ++ x, y = centers[i] ++ boundary_r = min(x, 1 - x, y, 1 - y) ++ radii[i] = max(0.0, min(radii[i], boundary_r)) ++ + return radii + + ++def construct_packing(): ++ """ ++ Constructs a high-density arrangement of 26 circles by initially placing ++ them in a deformed grid and then iteratively refining their positions ++ using a two-stage adaptive force-directed relaxation. ++ ++ Returns: ++ Tuple of (centers, radii) ++ centers: np.array of shape (26, 2) with (x, y) coordinates ++ radii: np.array of shape (26) with radius of each circle ++ """ ++ n = 26 ++ centers = np.zeros((n, 2)) ++ ++ # 1. Initial Grid for 25 circles: Start with a 5x5 grid. ++ x_coords = np.linspace(0.1, 0.9, 5) ++ y_coords = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords, y_coords) ++ base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T ++ ++ # 2. Place the 26th circle in a central interstitial void (0.4, 0.4). ++ void_center = np.array([0.4, 0.4]) # Keeping this as a good starting point ++ ++ # 3. Apply a Gaussian deformation to the 25 grid circles. ++ deformed_centers_25 = np.copy(base_centers_25) ++ ++ # Tuned hyperparameters for the Gaussian push based on prior successful runs: ++ amplitude = 0.045 # Slightly increased amplitude for more initial separation than previous 0.04 or 0.042 ++ sigma = 0.15 # Spread of the Gaussian, defines influence range ++ ++ for i in range(25): ++ pos_vector = base_centers_25[i] - void_center ++ dist_sq = np.sum(pos_vector**2) ++ ++ push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) ++ ++ if np.linalg.norm(pos_vector) > EPSILON: # Use EPSILON for robustness ++ direction = pos_vector / np.linalg.norm(pos_vector) ++ displacement = direction * push_magnitude ++ deformed_centers_25[i] += displacement ++ ++ # Combine deformed 25 circles with the 26th. ++ centers[:25] = deformed_centers_25 ++ centers[25] = void_center ++ centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Ensure centers remain strictly within bounds, using EPSILON ++ ++ # 4. Two-Stage Adaptive Force-Directed Relaxation. (Re-introduced from Inspiration 1-3, with tuning) ++ ++ # Shared parameters for both stages: ++ repulsion_threshold = 0.205 # Increased from 0.185 to encourage tighter packing before repelling ++ boundary_margin = 0.035 # Decreased from 0.04 to allow circles closer to boundary ++ ++ # Stage 1: Exploration - Broad adjustment and global distribution ++ exploration_iters = 150 # Increased iterations for broader exploration ++ exploration_step_size = 0.003 # Slightly increased step size ++ exploration_repulsion_strength = 0.02 # Increased repulsion strength ++ exploration_boundary_strength = 0.1 # Increased boundary repulsion strength ++ ++ for _ in range(exploration_iters): ++ forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ # Apply repulsion if distance is less than threshold ++ if 0 < dist < repulsion_threshold: ++ # Force inversely proportional to distance, stronger when closer ++ force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n): ++ x, y = centers[i] ++ # Use stronger force near boundaries ++ if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers += exploration_step_size * forces ++ centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Clip using EPSILON ++ ++ # Stage 2: Refinement - Fine-tuning and precise adjustments ++ refinement_iters = 200 # Increased iterations for finer convergence ++ refinement_step_size = 0.001 # Slightly increased step size ++ refinement_repulsion_strength = 0.008 # Slightly increased repulsion ++ refinement_boundary_strength = 0.04 # Slightly increased boundary repulsion ++ ++ for _ in range(refinement_iters): ++ forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers += refinement_step_size * forces ++ centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Clip using EPSILON ++ ++ # 5. Compute maximum valid radii for the final, refined configuration. ++ radii = compute_max_radii(centers) ++ return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/main.py new file mode 100644 index 0000000000000000000000000000000000000000..38e5303723911ef3f8110ce8c755e433d11787fb --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/main.py @@ -0,0 +1,204 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +# A small epsilon for floating point comparisons to avoid issues with exact equality or near-zero values. +EPSILON = 1e-12 # Using a smaller epsilon for higher precision in radius calculations and general robustness + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + radii[i] = max(radii[i], EPSILON) # Ensure a small positive radius to prevent division by zero later + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + # The proportional scaling mechanism is efficient in reducing overlaps. + for _ in range(500): # Fixed number of iterations for robustness (from Inspiration 4) + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + # Using EPSILON here for precision (from Inspiration 4) + if radii[i] + radii[j] > dist + EPSILON: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + + # Avoid division by zero if radii are extremely small (from Inspiration 4) + if sum_r < EPSILON: + radii[i] = 0.0 # Set to zero if they are effectively non-existent + radii[j] = 0.0 + changed_in_pass = True # Mark as changed to continue iterations + continue + + scale = dist / sum_r + + # Apply scaling. Only mark as changed if actual reduction happens (from Inspiration 4) + if scale < 1.0 - EPSILON: # Check for a meaningful reduction + radii[i] *= scale + radii[j] *= scale + changed_in_pass = True + + # If a full pass resulted in no significant changes, the packing is stable. + if not changed_in_pass: + break + + # Final check to ensure radii are non-negative and respect boundary limits (from Inspiration 4) + for i in range(n): + x, y = centers[i] + boundary_r = min(x, 1 - x, y, 1 - y) + radii[i] = max(0.0, min(radii[i], boundary_r)) + + return radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by initially placing + them in a deformed grid and then iteratively refining their positions + using a two-stage adaptive force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a central interstitial void (0.4, 0.4). + void_center = np.array([0.4, 0.4]) # Keeping this as a good starting point + + # 3. Apply a Gaussian deformation to the 25 grid circles. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push based on prior successful runs: + amplitude = 0.045 # Slightly increased amplitude for more initial separation than previous 0.04 or 0.042 + sigma = 0.15 # Spread of the Gaussian, defines influence range + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + if np.linalg.norm(pos_vector) > EPSILON: # Use EPSILON for robustness + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Ensure centers remain strictly within bounds, using EPSILON + + # 4. Two-Stage Adaptive Force-Directed Relaxation. (Re-introduced from Inspiration 1-3, with tuning) + + # Shared parameters for both stages: + repulsion_threshold = 0.205 # Increased from 0.185 to encourage tighter packing before repelling + boundary_margin = 0.035 # Decreased from 0.04 to allow circles closer to boundary + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 150 # Increased iterations for broader exploration + exploration_step_size = 0.003 # Slightly increased step size + exploration_repulsion_strength = 0.02 # Increased repulsion strength + exploration_boundary_strength = 0.1 # Increased boundary repulsion strength + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + # Apply repulsion if distance is less than threshold + if 0 < dist < repulsion_threshold: + # Force inversely proportional to distance, stronger when closer + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + # Use stronger force near boundaries + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Clip using EPSILON + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 200 # Increased iterations for finer convergence + refinement_step_size = 0.001 # Slightly increased step size + refinement_repulsion_strength = 0.008 # Slightly increased repulsion + refinement_boundary_strength = 0.04 # Slightly increased boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Clip using EPSILON + + # 5. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/original.py new file mode 100644 index 0000000000000000000000000000000000000000..e58791c9527c52e8afcb2cc5f4f5e25868e42d62 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/original.py @@ -0,0 +1,122 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.04 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the new configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..deee93814acf6b7d296a2165e7cd12b47aea7298 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_38/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_38/results +Run 1/1 completed in 0.46 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9634680581772046 + public: {'centers_str': ' centers[0] = (0.0991, 0.0991)\n centers[1] = (0.2988, 0.0943)\n centers[2] = (0.5012, 0.0943)\n centers[3] = (0.7006, 0.0991)\n centers[4] = (0.9003, 0.0997)\n centers[5] = (0.0943, 0.2988)\n centers[6] = (0.2791, 0.2791)\n centers[7] = (0.5209, 0.2791)\n centers[8] = (0.7052, 0.2988)\n centers[9] = (0.9007, 0.3000)\n centers[10] = (0.0943, 0.5012)\n centers[11] = (0.2791, 0.5209)\n centers[12] = (0.5209, 0.5209)\n centers[13] = (0.7052, 0.5012)\n centers[14] = (0.9007, 0.5000)\n centers[15] = (0.0991, 0.7006)\n centers[16] = (0.2988, 0.7052)\n centers[17] = (0.5012, 0.7052)\n centers[18] = (0.7006, 0.7006)\n centers[19] = (0.9003, 0.7000)\n centers[20] = (0.0997, 0.9003)\n centers[21] = (0.3000, 0.9007)\n centers[22] = (0.5000, 0.9007)\n centers[23] = (0.7000, 0.9003)\n centers[24] = (0.9003, 0.9003)\n centers[25] = (0.4000, 0.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9634680581772046} + visualization_path: + execution_time_mean: 0.46216494170948863 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..f02d516ed179f9d8cceb370b14d040f0183a3d12 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9634680581772046, + "public": { + "centers_str": " centers[0] = (0.0991, 0.0991)\n centers[1] = (0.2988, 0.0943)\n centers[2] = (0.5012, 0.0943)\n centers[3] = (0.7006, 0.0991)\n centers[4] = (0.9003, 0.0997)\n centers[5] = (0.0943, 0.2988)\n centers[6] = (0.2791, 0.2791)\n centers[7] = (0.5209, 0.2791)\n centers[8] = (0.7052, 0.2988)\n centers[9] = (0.9007, 0.3000)\n centers[10] = (0.0943, 0.5012)\n centers[11] = (0.2791, 0.5209)\n centers[12] = (0.5209, 0.5209)\n centers[13] = (0.7052, 0.5012)\n centers[14] = (0.9007, 0.5000)\n centers[15] = (0.0991, 0.7006)\n centers[16] = (0.2988, 0.7052)\n centers[17] = (0.5012, 0.7052)\n centers[18] = (0.7006, 0.7006)\n centers[19] = (0.9003, 0.7000)\n centers[20] = (0.0997, 0.9003)\n centers[21] = (0.3000, 0.9007)\n centers[22] = (0.5000, 0.9007)\n centers[23] = (0.7000, 0.9003)\n centers[24] = (0.9003, 0.9003)\n centers[25] = (0.4000, 0.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9634680581772046 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_38/results/packing_viz.png", + "execution_time_mean": 0.46216494170948863, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..c4219a8a410e978bc4f13cce8c02393d9587185d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_38/rewrite.txt @@ -0,0 +1,195 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +# A small epsilon for floating point comparisons to avoid issues with exact equality or near-zero values. +EPSILON = 1e-12 # Using a smaller epsilon for higher precision in radius calculations and general robustness + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + radii[i] = max(radii[i], EPSILON) # Ensure a small positive radius to prevent division by zero later + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + # The proportional scaling mechanism is efficient in reducing overlaps. + for _ in range(500): # Fixed number of iterations for robustness (from Inspiration 4) + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + # Using EPSILON here for precision (from Inspiration 4) + if radii[i] + radii[j] > dist + EPSILON: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + + # Avoid division by zero if radii are extremely small (from Inspiration 4) + if sum_r < EPSILON: + radii[i] = 0.0 # Set to zero if they are effectively non-existent + radii[j] = 0.0 + changed_in_pass = True # Mark as changed to continue iterations + continue + + scale = dist / sum_r + + # Apply scaling. Only mark as changed if actual reduction happens (from Inspiration 4) + if scale < 1.0 - EPSILON: # Check for a meaningful reduction + radii[i] *= scale + radii[j] *= scale + changed_in_pass = True + + # If a full pass resulted in no significant changes, the packing is stable. + if not changed_in_pass: + break + + # Final check to ensure radii are non-negative and respect boundary limits (from Inspiration 4) + for i in range(n): + x, y = centers[i] + boundary_r = min(x, 1 - x, y, 1 - y) + radii[i] = max(0.0, min(radii[i], boundary_r)) + + return radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by initially placing + them in a deformed grid and then iteratively refining their positions + using a two-stage adaptive force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a central interstitial void (0.4, 0.4). + void_center = np.array([0.4, 0.4]) # Keeping this as a good starting point + + # 3. Apply a Gaussian deformation to the 25 grid circles. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push based on prior successful runs: + amplitude = 0.045 # Slightly increased amplitude for more initial separation than previous 0.04 or 0.042 + sigma = 0.15 # Spread of the Gaussian, defines influence range + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + if np.linalg.norm(pos_vector) > EPSILON: # Use EPSILON for robustness + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Ensure centers remain strictly within bounds, using EPSILON + + # 4. Two-Stage Adaptive Force-Directed Relaxation. (Re-introduced from Inspiration 1-3, with tuning) + + # Shared parameters for both stages: + repulsion_threshold = 0.205 # Increased from 0.185 to encourage tighter packing before repelling + boundary_margin = 0.035 # Decreased from 0.04 to allow circles closer to boundary + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 150 # Increased iterations for broader exploration + exploration_step_size = 0.003 # Slightly increased step size + exploration_repulsion_strength = 0.02 # Increased repulsion strength + exploration_boundary_strength = 0.1 # Increased boundary repulsion strength + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + # Apply repulsion if distance is less than threshold + if 0 < dist < repulsion_threshold: + # Force inversely proportional to distance, stronger when closer + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + # Use stronger force near boundaries + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Clip using EPSILON + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 200 # Increased iterations for finer convergence + refinement_step_size = 0.001 # Slightly increased step size + refinement_repulsion_strength = 0.008 # Slightly increased repulsion + refinement_boundary_strength = 0.04 # Slightly increased boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Clip using EPSILON + + # 5. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_39/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_39/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_39/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_39/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_39/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..bb62b563e945dc2e7bf7e41c430f629aa916e946 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_39/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9635652269686839, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9635652269686839 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_39/results/packing_viz.png", + "execution_time_mean": 0.2459972002543509, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3cc96a8348495f57c89a72cb75235d2c3bd3cdbd Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..f2b6124235ffcbee8f47514045629f5bb442472d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_4/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_4/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.579964179622321 + public: {'centers_str': ' centers[0] = (0.1250, 0.0833)\n centers[1] = (0.3750, 0.0833)\n centers[2] = (0.6250, 0.0833)\n centers[3] = (0.8750, 0.0833)\n centers[4] = (0.2000, 0.2500)\n centers[5] = (0.4000, 0.2500)\n centers[6] = (0.6000, 0.2500)\n centers[7] = (0.8000, 0.2500)\n centers[8] = (0.1000, 0.4167)\n centers[9] = (0.3000, 0.4167)\n centers[10] = (0.5000, 0.4167)\n centers[11] = (0.7000, 0.4167)\n centers[12] = (0.9000, 0.4167)\n centers[13] = (0.1667, 0.5833)\n centers[14] = (0.3333, 0.5833)\n centers[15] = (0.5000, 0.5833)\n centers[16] = (0.6667, 0.5833)\n centers[17] = (0.8333, 0.5833)\n centers[18] = (0.1250, 0.7500)\n centers[19] = (0.3750, 0.7500)\n centers[20] = (0.6250, 0.7500)\n centers[21] = (0.8750, 0.7500)\n centers[22] = (0.2000, 0.9167)\n centers[23] = (0.4000, 0.9167)\n centers[24] = (0.6000, 0.9167)\n centers[25] = (0.8000, 0.9167)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.579964179622321} + visualization_path: + execution_time_mean: 0.0020483480766415596 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..3a74757c5f8fdc92688ec4003a4c1fe20756591a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.579964179622321, + "public": { + "centers_str": " centers[0] = (0.1250, 0.0833)\n centers[1] = (0.3750, 0.0833)\n centers[2] = (0.6250, 0.0833)\n centers[3] = (0.8750, 0.0833)\n centers[4] = (0.2000, 0.2500)\n centers[5] = (0.4000, 0.2500)\n centers[6] = (0.6000, 0.2500)\n centers[7] = (0.8000, 0.2500)\n centers[8] = (0.1000, 0.4167)\n centers[9] = (0.3000, 0.4167)\n centers[10] = (0.5000, 0.4167)\n centers[11] = (0.7000, 0.4167)\n centers[12] = (0.9000, 0.4167)\n centers[13] = (0.1667, 0.5833)\n centers[14] = (0.3333, 0.5833)\n centers[15] = (0.5000, 0.5833)\n centers[16] = (0.6667, 0.5833)\n centers[17] = (0.8333, 0.5833)\n centers[18] = (0.1250, 0.7500)\n centers[19] = (0.3750, 0.7500)\n centers[20] = (0.6250, 0.7500)\n centers[21] = (0.8750, 0.7500)\n centers[22] = (0.2000, 0.9167)\n centers[23] = (0.4000, 0.9167)\n centers[24] = (0.6000, 0.9167)\n centers[25] = (0.8000, 0.9167)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.579964179622321 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_4/results/packing_viz.png", + "execution_time_mean": 0.0020483480766415596, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d238c8236ac0f2fe5e32145ee7ab9b7a8c3175d1 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..296a0b832a542db9cfcde3a338af19d446e766f5 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/edit.diff @@ -0,0 +1,121 @@ +--- a/original.py ++++ b/original.py +@@ -1,116 +1,116 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. This method uses a + Gaussian deformation of a 5x5 grid to create space for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with 25 circles in a 5x5 grid (optimal for n=25) + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define a void and apply a Gaussian repulsive force to deform the grid + void_center = np.array([0.4, 0.4]) +- amplitude = 0.05 # Increased displacement magnitude +- sigma = 0.2 # Increased range of the repulsive force ++ amplitude = 0.035 # Reduced displacement magnitude to balance circle sizes ++ sigma = 0.2 # Range of the repulsive force (kept same) + + # Deform the 25 grid points + # Using a vectorized approach for displacement calculation + displacements = centers[:25] - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center (though unlikely here) + mask = distances > 1e-6 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + deformed_displacements = displacements.copy() + deformed_displacements[mask] /= distances[mask, np.newaxis] + centers[:25] += deformed_displacements * push_magnitudes[:, np.newaxis] + + + # 3. Place the 26th circle into the created void + centers[25] = void_center + + # Clipping is a safeguard against pushing centers outside the square. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this new configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/main.py new file mode 100644 index 0000000000000000000000000000000000000000..d25f6b89541046098dd8178ebe3044687856cfb8 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/main.py @@ -0,0 +1,116 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. This method uses a + Gaussian deformation of a 5x5 grid to create space for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with 25 circles in a 5x5 grid (optimal for n=25) + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define a void and apply a Gaussian repulsive force to deform the grid + void_center = np.array([0.4, 0.4]) + amplitude = 0.035 # Reduced displacement magnitude to balance circle sizes + sigma = 0.2 # Range of the repulsive force (kept same) + + # Deform the 25 grid points + # Using a vectorized approach for displacement calculation + displacements = centers[:25] - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center (though unlikely here) + mask = distances > 1e-6 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + deformed_displacements = displacements.copy() + deformed_displacements[mask] /= distances[mask, np.newaxis] + centers[:25] += deformed_displacements * push_magnitudes[:, np.newaxis] + + + # 3. Place the 26th circle into the created void + centers[25] = void_center + + # Clipping is a safeguard against pushing centers outside the square. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this new configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/original.py new file mode 100644 index 0000000000000000000000000000000000000000..dee65380a0907bf716192278e95a9d4b97bbaaa5 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/original.py @@ -0,0 +1,116 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. This method uses a + Gaussian deformation of a 5x5 grid to create space for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with 25 circles in a 5x5 grid (optimal for n=25) + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define a void and apply a Gaussian repulsive force to deform the grid + void_center = np.array([0.4, 0.4]) + amplitude = 0.05 # Increased displacement magnitude + sigma = 0.2 # Increased range of the repulsive force + + # Deform the 25 grid points + # Using a vectorized approach for displacement calculation + displacements = centers[:25] - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center (though unlikely here) + mask = distances > 1e-6 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + deformed_displacements = displacements.copy() + deformed_displacements[mask] /= distances[mask, np.newaxis] + centers[:25] += deformed_displacements * push_magnitudes[:, np.newaxis] + + + # 3. Place the 26th circle into the created void + centers[25] = void_center + + # Clipping is a safeguard against pushing centers outside the square. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this new configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..7a71379a8ca235ffdf66ad2bd606bf9f9e9ab02b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_40/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_40/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9540293517253406 + public: {'centers_str': ' centers[0] = (0.0974, 0.0974)\n centers[1] = (0.2968, 0.0905)\n centers[2] = (0.5032, 0.0905)\n centers[3] = (0.7026, 0.0974)\n centers[4] = (0.9004, 0.0997)\n centers[5] = (0.0905, 0.2968)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7095, 0.2968)\n centers[9] = (0.9013, 0.2997)\n centers[10] = (0.0905, 0.5032)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7095, 0.5032)\n centers[14] = (0.9013, 0.5003)\n centers[15] = (0.0974, 0.7026)\n centers[16] = (0.2968, 0.7095)\n centers[17] = (0.5032, 0.7095)\n centers[18] = (0.7026, 0.7026)\n centers[19] = (0.9004, 0.7003)\n centers[20] = (0.0997, 0.9004)\n centers[21] = (0.2997, 0.9013)\n centers[22] = (0.5003, 0.9013)\n centers[23] = (0.7003, 0.9004)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9540293517253406} + visualization_path: + execution_time_mean: 0.004207191988825798 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..1dc16094dc1e2d2b2f4ceaacdb319c8ff1beaea9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9540293517253406, + "public": { + "centers_str": " centers[0] = (0.0974, 0.0974)\n centers[1] = (0.2968, 0.0905)\n centers[2] = (0.5032, 0.0905)\n centers[3] = (0.7026, 0.0974)\n centers[4] = (0.9004, 0.0997)\n centers[5] = (0.0905, 0.2968)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7095, 0.2968)\n centers[9] = (0.9013, 0.2997)\n centers[10] = (0.0905, 0.5032)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7095, 0.5032)\n centers[14] = (0.9013, 0.5003)\n centers[15] = (0.0974, 0.7026)\n centers[16] = (0.2968, 0.7095)\n centers[17] = (0.5032, 0.7095)\n centers[18] = (0.7026, 0.7026)\n centers[19] = (0.9004, 0.7003)\n centers[20] = (0.0997, 0.9004)\n centers[21] = (0.2997, 0.9013)\n centers[22] = (0.5003, 0.9013)\n centers[23] = (0.7003, 0.9004)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9540293517253406 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_40/results/packing_viz.png", + "execution_time_mean": 0.004207191988825798, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..fccb4ef0913fcafa6d11dc2855c44355e5fcbf18 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_40/search_replace.txt @@ -0,0 +1,14 @@ + +A significant visual imbalance is observed where the central circle is very large, while the four circles immediately surrounding it are unusually small. This suggests that the Gaussian repulsive force might be too strong (`amplitude`), causing the surrounding circles to be pushed too far away from the void center, leading to their extreme shrinkage when radii are computed. Reducing the `amplitude` should result in a smaller central void, allowing the 26th circle to be smaller but enabling its neighbors to expand, leading to a more balanced packing and a higher total sum of radii. + + +<<<<<<< SEARCH + void_center = np.array([0.4, 0.4]) + amplitude = 0.05 # Increased displacement magnitude + sigma = 0.2 # Increased range of the repulsive force +======= + void_center = np.array([0.4, 0.4]) + amplitude = 0.035 # Reduced displacement magnitude to balance circle sizes + sigma = 0.2 # Range of the repulsive force (kept same) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2987fef76f68a61ac61c3d694674c659540dd246 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..093a3aed5b7c107e87e30b4040f6dee2cbdf7c59 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/edit.diff @@ -0,0 +1,362 @@ +--- a/original.py ++++ b/original.py +@@ -1,197 +1,197 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" ++"""Object-oriented circle packing for n=26 circles with a simulated annealing 'jiggle' step.""" + + import numpy as np + ++class Packer: ++ """ ++ An object-oriented class to manage the state and process of circle packing. ++ It encapsulates the circle centers and provides methods for initialization, ++ relaxation, and optimization. ++ """ ++ def __init__(self, n, config): ++ self.n = n ++ self.config = config ++ self.centers = np.zeros((self.n, 2)) ++ self.radii = np.zeros(self.n) + +-def construct_packing(): +- """ +- Construct a specific arrangement of 26 circles in a unit square +- that attempts to maximize the sum of their radii. ++ def initialize_state(self): ++ """ ++ Sets up the initial state: a 5x5 grid with a Gaussian push to accommodate ++ the 26th circle placed in an interstitial void. ++ """ ++ # 1. Base 5x5 grid for 25 circles ++ x_coords = np.linspace(0.1, 0.9, 5) ++ y_coords = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords, y_coords) ++ base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- Returns: +- Tuple of (centers, radii, sum_of_radii) +- centers: np.array of shape (26, 2) with (x, y) coordinates +- radii: np.array of shape (26) with radius of each circle +- sum_of_radii: Sum of all radii +- """ +- # Initialize arrays for 26 circles +- n = 26 +- centers = np.zeros((n, 2)) ++ # 2. Define void for 26th circle ++ void_center = np.array(self.config['void_center']) + +- # 1. Start with the 25 centers of a 5x5 grid. +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T ++ # 3. Apply Gaussian deformation push ++ deformed_centers_25 = np.copy(base_centers_25) ++ amplitude = self.config['gauss_amplitude'] ++ sigma = self.config['gauss_sigma'] + +- # 2. Define the center of the void where the 26th circle will be placed. +- # A central interstitial void at (0.4, 0.4) is a good candidate. +- void_center = np.array([0.4, 0.4]) ++ for i in range(25): ++ pos_vector = base_centers_25[i] - void_center ++ dist_sq = np.sum(pos_vector**2) ++ push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) ++ ++ if np.linalg.norm(pos_vector) > 1e-9: ++ direction = pos_vector / np.linalg.norm(pos_vector) ++ deformed_centers_25[i] += direction * push_magnitude + +- # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. +- # This pushes nearby circles away to make more room. +- deformed_centers_25 = np.copy(base_centers_25) ++ self.centers[:25] = deformed_centers_25 ++ self.centers[25] = void_center ++ self.centers = np.clip(self.centers, 0.0, 1.0) + +- # Hyperparameters for the Gaussian push: +- amplitude = 0.042 # The maximum distance to push a circle. Slightly increased for more initial separation. +- sigma = 0.15 # The "spread" of the push, controlling its influence range. +- +- for i in range(25): +- pos_vector = base_centers_25[i] - void_center +- dist_sq = np.sum(pos_vector**2) +- +- # Gaussian function defines the push magnitude based on distance from the void center. +- push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) +- +- # The push is directed radially away from the void center. +- if np.linalg.norm(pos_vector) > 1e-9: +- direction = pos_vector / np.linalg.norm(pos_vector) +- displacement = direction * push_magnitude +- deformed_centers_25[i] += displacement +- +- # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. +- centers[:25] = deformed_centers_25 +- centers[25] = void_center +- +- # Clip centers to ensure they stay within the square, although the push is gentle. +- centers = np.clip(centers, 0.0, 1.0) +- +- # 5. Two-Stage Adaptive Force-Directed Relaxation. +- # This improves upon simple iterative refinement by using different +- # force parameters for exploration (global adjustment) and refinement (fine-tuning). +- +- # Shared parameters for both stages: +- repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) +- boundary_margin = 0.04 # How close circles can get to boundary before repulsion +- +- # Stage 1: Exploration - Broad adjustment and global distribution +- # Aims to rapidly resolve initial overlaps and broadly distribute circles. +- exploration_iters = 100 +- exploration_step_size = 0.0025 +- exploration_repulsion_strength = 0.015 +- exploration_boundary_strength = 0.075 +- +- for _ in range(exploration_iters): +- forces = np.zeros_like(centers) +- ++ def _relax_step(self, params): ++ """ ++ Performs a single step of force-directed relaxation. ++ This is a unified method used by all relaxation stages. ++ """ ++ forces = np.zeros_like(self.centers) ++ + # Circle-circle repulsion +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] ++ for i in range(self.n): ++ for j in range(i + 1, self.n): ++ vec = self.centers[i] - self.centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist ++ if 0 < dist < params['repulsion_threshold']: ++ force_magnitude = params['repulsion_strength'] * (params['repulsion_threshold'] - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion +- for i in range(n): +- x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) ++ for i in range(self.n): ++ x, y = self.centers[i] ++ if x < params['boundary_margin']: forces[i, 0] += params['boundary_strength'] * (params['boundary_margin'] - x) ++ if x > 1 - params['boundary_margin']: forces[i, 0] -= params['boundary_strength'] * (x - (1 - params['boundary_margin'])) ++ if y < params['boundary_margin']: forces[i, 1] += params['boundary_strength'] * (params['boundary_margin'] - y) ++ if y > 1 - params['boundary_margin']: forces[i, 1] -= params['boundary_strength'] * (y - (1 - params['boundary_margin'])) ++ ++ self.centers += params['step_size'] * forces ++ self.centers = np.clip(self.centers, 0.0, 1.0) + +- centers += exploration_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) ++ def run_relaxation_schedule(self, stage_name, iterations): ++ """Runs a relaxation stage for a given number of iterations.""" ++ stage_params = self.config['relaxation_stages'][stage_name] ++ for _ in range(iterations): ++ self._relax_step(stage_params) + +- # Stage 2: Refinement - Fine-tuning and precise adjustments +- # Uses smaller movements to converge to a better local optimum. +- refinement_iters = 150 +- refinement_step_size = 0.0008 # Much smaller step size +- refinement_repulsion_strength = 0.005 # Weaker repulsion +- refinement_boundary_strength = 0.025 # Weaker boundary repulsion ++ def jiggle_packing(self, strength, central_indices, multiplier): ++ """ ++ Applies a random perturbation to circle centers to escape local optima. ++ A stronger jiggle is applied to a targeted central cluster. ++ """ ++ perturbations = np.random.uniform(-strength, strength, self.centers.shape) ++ perturbations[central_indices] *= multiplier # Apply stronger jiggle to central circles ++ self.centers += perturbations ++ self.centers = np.clip(self.centers, 0.0, 1.0) ++ ++ def compute_max_radii(self): ++ """ ++ Iteratively computes the maximum possible radii for the final configuration. ++ """ ++ radii = np.zeros(self.n) ++ for i in range(self.n): ++ x, y = self.centers[i] ++ radii[i] = min(x, 1 - x, y, 1 - y) + +- for _ in range(refinement_iters): +- forces = np.zeros_like(centers) +- +- # Circle-circle repulsion +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist +- force_vec = force_magnitude * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- +- # Boundary repulsion +- for i in range(n): +- x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) +- +- centers += refinement_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- +- # 6. Compute maximum valid radii for the final, refined configuration. +- radii = compute_max_radii(centers) +- return centers, radii ++ for _ in range(500): # Increased iterations for robustness ++ changes_made = False ++ for i in range(self.n): ++ for j in range(i + 1, self.n): ++ dist = np.linalg.norm(self.centers[i] - self.centers[j]) ++ if radii[i] + radii[j] > dist: ++ sum_r = radii[i] + radii[j] ++ if sum_r > 1e-9: ++ scale = dist / sum_r ++ ri_new, rj_new = radii[i] * scale, radii[j] * scale ++ if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: ++ radii[i], radii[j] = ri_new, rj_new ++ changes_made = True ++ if not changes_made: ++ break ++ self.radii = radii + + ++def construct_packing(): ++ """ ++ Constructs a high-density arrangement of 26 circles by orchestrating ++ a Packer object through initialization, relaxation, and annealing. ++ """ ++ n = 26 ++ ++ # Configuration dictionary for all hyperparameters ++ config = { ++ 'void_center': (0.4, 0.4), ++ 'gauss_amplitude': 0.042, ++ 'gauss_sigma': 0.15, ++ 'relaxation_stages': { ++ 'explore': { ++ 'step_size': 0.0025, 'repulsion_strength': 0.015, ++ 'boundary_strength': 0.075, 'repulsion_threshold': 0.185, ++ 'boundary_margin': 0.04 ++ }, ++ 'refine': { ++ 'step_size': 0.0008, 'repulsion_strength': 0.005, ++ 'boundary_strength': 0.025, 'repulsion_threshold': 0.185, ++ 'boundary_margin': 0.04 ++ }, ++ 'post_jiggle_refine': { ++ 'step_size': 0.0005, 'repulsion_strength': 0.003, ++ 'boundary_strength': 0.02, 'repulsion_threshold': 0.185, ++ 'boundary_margin': 0.035 ++ } ++ } ++ } ++ ++ # --- Orchestration --- ++ packer = Packer(n, config) ++ ++ # 1. Initial state based on Gaussian push ++ packer.initialize_state() ++ ++ # 2. Initial two-stage relaxation ++ packer.run_relaxation_schedule('explore', iterations=100) ++ packer.run_relaxation_schedule('refine', iterations=150) ++ ++ # 3. Jiggle the packing to escape local minimum, targeting the central cluster ++ # Indices of 8 grid neighbors + the central circle (25) ++ central_indices = [6, 7, 8, 11, 12, 13, 16, 17, 18, 25] ++ packer.jiggle_packing(strength=0.004, central_indices=central_indices, multiplier=2.0) ++ ++ # 4. Final fine-grained refinement post-jiggle ++ packer.run_relaxation_schedule('post_jiggle_refine', iterations=100) ++ ++ # 5. Compute the final radii ++ packer.compute_max_radii() ++ ++ return packer.centers, packer.radii ++ ++ ++# This function is not part of the class but is called by the external runner + def compute_max_radii(centers): + """ +- Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This is +- an iterative version that converges to a stable solution. +- +- Args: +- centers: np.array of shape (n, 2) with (x, y) coordinates +- +- Returns: +- np.array of shape (n) with radius of each circle ++ Wrapper function to maintain compatibility with the original program structure ++ that had a standalone compute_max_radii function. This is not used internally. ++ A more robust version is implemented inside the Packer class. + """ +- n = centers.shape[0] +- +- # Initialize radii based on distance to the square's boundaries. +- radii = np.zeros(n) +- for i in range(n): +- x, y = centers[i] +- radii[i] = min(x, 1 - x, y, 1 - y) +- +- # Iteratively resolve overlaps between circles until no more changes occur. +- # A high number of iterations ensures convergence for complex arrangements. +- for _ in range(300): +- changes_made = False +- # Check every pair of circles for overlap +- for i in range(n): +- for j in range(i + 1, n): +- dist = np.linalg.norm(centers[i] - centers[j]) +- +- # If they overlap +- if radii[i] + radii[j] > dist: +- sum_r = radii[i] + radii[j] +- if sum_r > 1e-9: # Avoid division by zero +- # Scale both radii proportionally to resolve the overlap. +- scale = dist / sum_r +- ri_new = radii[i] * scale +- rj_new = radii[j] * scale +- +- # Check for significant change to set the flag and update +- if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: +- radii[i] = ri_new +- radii[j] = rj_new +- changes_made = True +- +- # If a full pass resulted in no changes, the packing is stable. +- if not changes_made: +- break +- +- return radii +- +- ++ packer = Packer(centers.shape[0], {}) ++ packer.centers = centers ++ packer.compute_max_radii() ++ return packer.radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/main.py new file mode 100644 index 0000000000000000000000000000000000000000..1d5de43203c2ad8bfdd48b718898f98a37f44752 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/main.py @@ -0,0 +1,197 @@ +# EVOLVE-BLOCK-START +"""Object-oriented circle packing for n=26 circles with a simulated annealing 'jiggle' step.""" + +import numpy as np + +class Packer: + """ + An object-oriented class to manage the state and process of circle packing. + It encapsulates the circle centers and provides methods for initialization, + relaxation, and optimization. + """ + def __init__(self, n, config): + self.n = n + self.config = config + self.centers = np.zeros((self.n, 2)) + self.radii = np.zeros(self.n) + + def initialize_state(self): + """ + Sets up the initial state: a 5x5 grid with a Gaussian push to accommodate + the 26th circle placed in an interstitial void. + """ + # 1. Base 5x5 grid for 25 circles + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define void for 26th circle + void_center = np.array(self.config['void_center']) + + # 3. Apply Gaussian deformation push + deformed_centers_25 = np.copy(base_centers_25) + amplitude = self.config['gauss_amplitude'] + sigma = self.config['gauss_sigma'] + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + deformed_centers_25[i] += direction * push_magnitude + + self.centers[:25] = deformed_centers_25 + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _relax_step(self, params): + """ + Performs a single step of force-directed relaxation. + This is a unified method used by all relaxation stages. + """ + forces = np.zeros_like(self.centers) + + # Circle-circle repulsion + for i in range(self.n): + for j in range(i + 1, self.n): + vec = self.centers[i] - self.centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < params['repulsion_threshold']: + force_magnitude = params['repulsion_strength'] * (params['repulsion_threshold'] - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(self.n): + x, y = self.centers[i] + if x < params['boundary_margin']: forces[i, 0] += params['boundary_strength'] * (params['boundary_margin'] - x) + if x > 1 - params['boundary_margin']: forces[i, 0] -= params['boundary_strength'] * (x - (1 - params['boundary_margin'])) + if y < params['boundary_margin']: forces[i, 1] += params['boundary_strength'] * (params['boundary_margin'] - y) + if y > 1 - params['boundary_margin']: forces[i, 1] -= params['boundary_strength'] * (y - (1 - params['boundary_margin'])) + + self.centers += params['step_size'] * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def run_relaxation_schedule(self, stage_name, iterations): + """Runs a relaxation stage for a given number of iterations.""" + stage_params = self.config['relaxation_stages'][stage_name] + for _ in range(iterations): + self._relax_step(stage_params) + + def jiggle_packing(self, strength, central_indices, multiplier): + """ + Applies a random perturbation to circle centers to escape local optima. + A stronger jiggle is applied to a targeted central cluster. + """ + perturbations = np.random.uniform(-strength, strength, self.centers.shape) + perturbations[central_indices] *= multiplier # Apply stronger jiggle to central circles + self.centers += perturbations + self.centers = np.clip(self.centers, 0.0, 1.0) + + def compute_max_radii(self): + """ + Iteratively computes the maximum possible radii for the final configuration. + """ + radii = np.zeros(self.n) + for i in range(self.n): + x, y = self.centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + for _ in range(500): # Increased iterations for robustness + changes_made = False + for i in range(self.n): + for j in range(i + 1, self.n): + dist = np.linalg.norm(self.centers[i] - self.centers[j]) + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + self.radii = radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by orchestrating + a Packer object through initialization, relaxation, and annealing. + """ + n = 26 + + # Configuration dictionary for all hyperparameters + config = { + 'void_center': (0.4, 0.4), + 'gauss_amplitude': 0.042, + 'gauss_sigma': 0.15, + 'relaxation_stages': { + 'explore': { + 'step_size': 0.0025, 'repulsion_strength': 0.015, + 'boundary_strength': 0.075, 'repulsion_threshold': 0.185, + 'boundary_margin': 0.04 + }, + 'refine': { + 'step_size': 0.0008, 'repulsion_strength': 0.005, + 'boundary_strength': 0.025, 'repulsion_threshold': 0.185, + 'boundary_margin': 0.04 + }, + 'post_jiggle_refine': { + 'step_size': 0.0005, 'repulsion_strength': 0.003, + 'boundary_strength': 0.02, 'repulsion_threshold': 0.185, + 'boundary_margin': 0.035 + } + } + } + + # --- Orchestration --- + packer = Packer(n, config) + + # 1. Initial state based on Gaussian push + packer.initialize_state() + + # 2. Initial two-stage relaxation + packer.run_relaxation_schedule('explore', iterations=100) + packer.run_relaxation_schedule('refine', iterations=150) + + # 3. Jiggle the packing to escape local minimum, targeting the central cluster + # Indices of 8 grid neighbors + the central circle (25) + central_indices = [6, 7, 8, 11, 12, 13, 16, 17, 18, 25] + packer.jiggle_packing(strength=0.004, central_indices=central_indices, multiplier=2.0) + + # 4. Final fine-grained refinement post-jiggle + packer.run_relaxation_schedule('post_jiggle_refine', iterations=100) + + # 5. Compute the final radii + packer.compute_max_radii() + + return packer.centers, packer.radii + + +# This function is not part of the class but is called by the external runner +def compute_max_radii(centers): + """ + Wrapper function to maintain compatibility with the original program structure + that had a standalone compute_max_radii function. This is not used internally. + A more robust version is implemented inside the Packer class. + """ + packer = Packer(centers.shape[0], {}) + packer.centers = centers + packer.compute_max_radii() + return packer.radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/original.py new file mode 100644 index 0000000000000000000000000000000000000000..986a6216785f4bfc5a55321983717adfc5c3b23c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/original.py @@ -0,0 +1,197 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. Slightly increased for more initial separation. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) + boundary_margin = 0.04 # How close circles can get to boundary before repulsion + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(300): + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero + # Scale both radii proportionally to resolve the overlap. + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag and update + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..6481cb217b3b6e95baab86f667422a70444f04bc --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_42/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_42/results +Run 1/1 completed in 0.41 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9391311297531073 + public: {'centers_str': ' centers[0] = (0.1011, 0.0982)\n centers[1] = (0.2964, 0.0963)\n centers[2] = (0.5020, 0.0935)\n centers[3] = (0.7035, 0.0959)\n centers[4] = (0.8981, 0.0993)\n centers[5] = (0.0982, 0.2984)\n centers[6] = (0.2767, 0.2759)\n centers[7] = (0.5124, 0.2840)\n centers[8] = (0.6986, 0.3065)\n centers[9] = (0.9005, 0.3032)\n centers[10] = (0.0945, 0.4980)\n centers[11] = (0.2778, 0.5136)\n centers[12] = (0.5161, 0.5167)\n centers[13] = (0.7036, 0.5058)\n centers[14] = (0.8978, 0.4989)\n centers[15] = (0.0985, 0.6997)\n centers[16] = (0.3045, 0.7005)\n centers[17] = (0.4968, 0.7000)\n centers[18] = (0.7021, 0.6934)\n centers[19] = (0.8995, 0.6967)\n centers[20] = (0.1006, 0.9009)\n centers[21] = (0.3008, 0.8969)\n centers[22] = (0.5006, 0.8988)\n centers[23] = (0.6971, 0.8999)\n centers[24] = (0.9014, 0.8994)\n centers[25] = (0.4052, 0.4078)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9391311297531073} + visualization_path: + execution_time_mean: 0.41481981286779046 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..bcab6f2ad0ff763ebd5a037737dd0f6b63f70649 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9391311297531073, + "public": { + "centers_str": " centers[0] = (0.1011, 0.0982)\n centers[1] = (0.2964, 0.0963)\n centers[2] = (0.5020, 0.0935)\n centers[3] = (0.7035, 0.0959)\n centers[4] = (0.8981, 0.0993)\n centers[5] = (0.0982, 0.2984)\n centers[6] = (0.2767, 0.2759)\n centers[7] = (0.5124, 0.2840)\n centers[8] = (0.6986, 0.3065)\n centers[9] = (0.9005, 0.3032)\n centers[10] = (0.0945, 0.4980)\n centers[11] = (0.2778, 0.5136)\n centers[12] = (0.5161, 0.5167)\n centers[13] = (0.7036, 0.5058)\n centers[14] = (0.8978, 0.4989)\n centers[15] = (0.0985, 0.6997)\n centers[16] = (0.3045, 0.7005)\n centers[17] = (0.4968, 0.7000)\n centers[18] = (0.7021, 0.6934)\n centers[19] = (0.8995, 0.6967)\n centers[20] = (0.1006, 0.9009)\n centers[21] = (0.3008, 0.8969)\n centers[22] = (0.5006, 0.8988)\n centers[23] = (0.6971, 0.8999)\n centers[24] = (0.9014, 0.8994)\n centers[25] = (0.4052, 0.4078)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9391311297531073 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_42/results/packing_viz.png", + "execution_time_mean": 0.41481981286779046, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..96691592979f37572170da7a556acd3f6465d79f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_42/rewrite.txt @@ -0,0 +1,188 @@ +# EVOLVE-BLOCK-START +"""Object-oriented circle packing for n=26 circles with a simulated annealing 'jiggle' step.""" + +import numpy as np + +class Packer: + """ + An object-oriented class to manage the state and process of circle packing. + It encapsulates the circle centers and provides methods for initialization, + relaxation, and optimization. + """ + def __init__(self, n, config): + self.n = n + self.config = config + self.centers = np.zeros((self.n, 2)) + self.radii = np.zeros(self.n) + + def initialize_state(self): + """ + Sets up the initial state: a 5x5 grid with a Gaussian push to accommodate + the 26th circle placed in an interstitial void. + """ + # 1. Base 5x5 grid for 25 circles + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define void for 26th circle + void_center = np.array(self.config['void_center']) + + # 3. Apply Gaussian deformation push + deformed_centers_25 = np.copy(base_centers_25) + amplitude = self.config['gauss_amplitude'] + sigma = self.config['gauss_sigma'] + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + deformed_centers_25[i] += direction * push_magnitude + + self.centers[:25] = deformed_centers_25 + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + + def _relax_step(self, params): + """ + Performs a single step of force-directed relaxation. + This is a unified method used by all relaxation stages. + """ + forces = np.zeros_like(self.centers) + + # Circle-circle repulsion + for i in range(self.n): + for j in range(i + 1, self.n): + vec = self.centers[i] - self.centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < params['repulsion_threshold']: + force_magnitude = params['repulsion_strength'] * (params['repulsion_threshold'] - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(self.n): + x, y = self.centers[i] + if x < params['boundary_margin']: forces[i, 0] += params['boundary_strength'] * (params['boundary_margin'] - x) + if x > 1 - params['boundary_margin']: forces[i, 0] -= params['boundary_strength'] * (x - (1 - params['boundary_margin'])) + if y < params['boundary_margin']: forces[i, 1] += params['boundary_strength'] * (params['boundary_margin'] - y) + if y > 1 - params['boundary_margin']: forces[i, 1] -= params['boundary_strength'] * (y - (1 - params['boundary_margin'])) + + self.centers += params['step_size'] * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + def run_relaxation_schedule(self, stage_name, iterations): + """Runs a relaxation stage for a given number of iterations.""" + stage_params = self.config['relaxation_stages'][stage_name] + for _ in range(iterations): + self._relax_step(stage_params) + + def jiggle_packing(self, strength, central_indices, multiplier): + """ + Applies a random perturbation to circle centers to escape local optima. + A stronger jiggle is applied to a targeted central cluster. + """ + perturbations = np.random.uniform(-strength, strength, self.centers.shape) + perturbations[central_indices] *= multiplier # Apply stronger jiggle to central circles + self.centers += perturbations + self.centers = np.clip(self.centers, 0.0, 1.0) + + def compute_max_radii(self): + """ + Iteratively computes the maximum possible radii for the final configuration. + """ + radii = np.zeros(self.n) + for i in range(self.n): + x, y = self.centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + for _ in range(500): # Increased iterations for robustness + changes_made = False + for i in range(self.n): + for j in range(i + 1, self.n): + dist = np.linalg.norm(self.centers[i] - self.centers[j]) + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: + scale = dist / sum_r + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i], radii[j] = ri_new, rj_new + changes_made = True + if not changes_made: + break + self.radii = radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by orchestrating + a Packer object through initialization, relaxation, and annealing. + """ + n = 26 + + # Configuration dictionary for all hyperparameters + config = { + 'void_center': (0.4, 0.4), + 'gauss_amplitude': 0.042, + 'gauss_sigma': 0.15, + 'relaxation_stages': { + 'explore': { + 'step_size': 0.0025, 'repulsion_strength': 0.015, + 'boundary_strength': 0.075, 'repulsion_threshold': 0.185, + 'boundary_margin': 0.04 + }, + 'refine': { + 'step_size': 0.0008, 'repulsion_strength': 0.005, + 'boundary_strength': 0.025, 'repulsion_threshold': 0.185, + 'boundary_margin': 0.04 + }, + 'post_jiggle_refine': { + 'step_size': 0.0005, 'repulsion_strength': 0.003, + 'boundary_strength': 0.02, 'repulsion_threshold': 0.185, + 'boundary_margin': 0.035 + } + } + } + + # --- Orchestration --- + packer = Packer(n, config) + + # 1. Initial state based on Gaussian push + packer.initialize_state() + + # 2. Initial two-stage relaxation + packer.run_relaxation_schedule('explore', iterations=100) + packer.run_relaxation_schedule('refine', iterations=150) + + # 3. Jiggle the packing to escape local minimum, targeting the central cluster + # Indices of 8 grid neighbors + the central circle (25) + central_indices = [6, 7, 8, 11, 12, 13, 16, 17, 18, 25] + packer.jiggle_packing(strength=0.004, central_indices=central_indices, multiplier=2.0) + + # 4. Final fine-grained refinement post-jiggle + packer.run_relaxation_schedule('post_jiggle_refine', iterations=100) + + # 5. Compute the final radii + packer.compute_max_radii() + + return packer.centers, packer.radii + + +# This function is not part of the class but is called by the external runner +def compute_max_radii(centers): + """ + Wrapper function to maintain compatibility with the original program structure + that had a standalone compute_max_radii function. This is not used internally. + A more robust version is implemented inside the Packer class. + """ + packer = Packer(centers.shape[0], {}) + packer.centers = centers + packer.compute_max_radii() + return packer.radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10c4c0966ff94a80b1f47356ed1fbd934c0d7154 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..7c54f3377d0e4bf666f14630bc93320303f5ad98 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/edit.diff @@ -0,0 +1,163 @@ +--- a/original.py ++++ b/original.py +@@ -1,122 +1,159 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.04 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + +- # 5. Compute maximum valid radii for the new configuration. ++ # 5. Iterative Refinement: Apply a gentle force-directed relaxation ++ # to allow circles to settle into a better local packing. This helps ++ # relieve pressure from the initial geometric placement. ++ refinement_iters = 150 ++ refinement_step_size = 0.0008 ++ refinement_repulsion_strength = 0.005 ++ refinement_boundary_strength = 0.025 ++ repulsion_threshold = 0.185 ++ boundary_margin = 0.04 ++ ++ n = centers.shape[0] # Get n for the loop ++ ++ for _ in range(refinement_iters): ++ forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers += refinement_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/main.py new file mode 100644 index 0000000000000000000000000000000000000000..a5fac9bc232f5ce1af3d3475ac6ae86d112107ba --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/main.py @@ -0,0 +1,159 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.04 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Iterative Refinement: Apply a gentle force-directed relaxation + # to allow circles to settle into a better local packing. This helps + # relieve pressure from the initial geometric placement. + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + repulsion_threshold = 0.185 + boundary_margin = 0.04 + + n = centers.shape[0] # Get n for the loop + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/original.py new file mode 100644 index 0000000000000000000000000000000000000000..484c597ade2d668efd70af855e38d71f03361b59 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/original.py @@ -0,0 +1,122 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.04 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the new configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..65f3056bfa7e39ef6652aa92a8600d14ec76b160 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_43/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_43/results +Run 1/1 completed in 0.18 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.961830838373212 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0959)\n centers[2] = (0.5014, 0.0959)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0959, 0.2986)\n centers[6] = (0.2818, 0.2818)\n centers[7] = (0.5182, 0.2818)\n centers[8] = (0.7041, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0959, 0.5014)\n centers[11] = (0.2818, 0.5182)\n centers[12] = (0.5182, 0.5182)\n centers[13] = (0.7041, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7041)\n centers[17] = (0.5014, 0.7041)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.961830838373212} + visualization_path: + execution_time_mean: 0.1758503820747137 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..05ef37908481e2e5d04c611256011ddb9946f953 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.961830838373212, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0959)\n centers[2] = (0.5014, 0.0959)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0959, 0.2986)\n centers[6] = (0.2818, 0.2818)\n centers[7] = (0.5182, 0.2818)\n centers[8] = (0.7041, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0959, 0.5014)\n centers[11] = (0.2818, 0.5182)\n centers[12] = (0.5182, 0.5182)\n centers[13] = (0.7041, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7041)\n centers[17] = (0.5014, 0.7041)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.961830838373212 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_43/results/packing_viz.png", + "execution_time_mean": 0.1758503820747137, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..9e1c8bfb259fec3e717de4f94bab5a986de38c03 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_43/search_replace.txt @@ -0,0 +1,62 @@ + +add_refinement_relaxation + + +Based on the visual feedback, the current configuration suffers from high pressure in the center, where several small circles are "crushed" by the large central circle that was inserted into the grid void. The current method only performs an initial geometric push and does not allow the circles to adjust their positions afterwards. This rigidity is the primary bottleneck preventing a higher sum of radii. + +To address this, I am introducing a single, gentle, force-directed relaxation stage. This stage runs after the initial Gaussian push and applies small repulsive forces between circles that are too close, as well as repulsion from the boundaries. By allowing the circle centers to move slightly, the system can settle into a lower-energy state, relieving the central pressure points. This should allow the previously crushed circles to expand and shift, leading to a more balanced distribution of radii and a higher overall sum. I am deliberately using conservative force parameters from a previous successful implementation to ensure a fine-tuning effect rather than a major, disruptive rearrangement of the already effective base structure. + + +<<<<<<< SEARCH + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the new configuration. + radii = compute_max_radii(centers) + return centers, radii +======= + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Iterative Refinement: Apply a gentle force-directed relaxation + # to allow circles to settle into a better local packing. This helps + # relieve pressure from the initial geometric placement. + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + repulsion_threshold = 0.185 + boundary_margin = 0.04 + + n = centers.shape[0] # Get n for the loop + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9645f050f7f8bf9e846ce485fd72849d73b5e37a Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..917d60d3c95c8d801c278ea0e463a17e077487b0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_45/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_45/results +Run 1/1 completed in 0.45 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9640176501420596 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0955)\n centers[2] = (0.5014, 0.0955)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0956, 0.2986)\n centers[6] = (0.2803, 0.2803)\n centers[7] = (0.5197, 0.2803)\n centers[8] = (0.7044, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0955, 0.5014)\n centers[11] = (0.2803, 0.5197)\n centers[12] = (0.5197, 0.5197)\n centers[13] = (0.7044, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7044)\n centers[17] = (0.5014, 0.7044)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9640176501420596} + visualization_path: + execution_time_mean: 0.45498125115409493 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..f9294c43067cd58195411d8ae6765be958eed7f3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9640176501420596, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0955)\n centers[2] = (0.5014, 0.0955)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0956, 0.2986)\n centers[6] = (0.2803, 0.2803)\n centers[7] = (0.5197, 0.2803)\n centers[8] = (0.7044, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0955, 0.5014)\n centers[11] = (0.2803, 0.5197)\n centers[12] = (0.5197, 0.5197)\n centers[13] = (0.7044, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7044)\n centers[17] = (0.5014, 0.7044)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9640176501420596 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_45/results/packing_viz.png", + "execution_time_mean": 0.45498125115409493, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a1251714d3bd5157a2a7184715d7bcbe7931b4f Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..6a2c2bf85121fe6fcd8fbd409f4f366f576f9cb7 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_46/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_46/results +Run 1/1 completed in 0.30 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9596919311655336 + public: {'centers_str': ' centers[0] = (0.0991, 0.0991)\n centers[1] = (0.2985, 0.0954)\n centers[2] = (0.5014, 0.0953)\n centers[3] = (0.7007, 0.0990)\n centers[4] = (0.9004, 0.0996)\n centers[5] = (0.0954, 0.2985)\n centers[6] = (0.2816, 0.2816)\n centers[7] = (0.5182, 0.2815)\n centers[8] = (0.7044, 0.2984)\n centers[9] = (0.9006, 0.2998)\n centers[10] = (0.0953, 0.5014)\n centers[11] = (0.2815, 0.5182)\n centers[12] = (0.5182, 0.5182)\n centers[13] = (0.7044, 0.5014)\n centers[14] = (0.9006, 0.5000)\n centers[15] = (0.0990, 0.7007)\n centers[16] = (0.2984, 0.7044)\n centers[17] = (0.5014, 0.7044)\n centers[18] = (0.7008, 0.7008)\n centers[19] = (0.9005, 0.7002)\n centers[20] = (0.0996, 0.9004)\n centers[21] = (0.2998, 0.9006)\n centers[22] = (0.5000, 0.9006)\n centers[23] = (0.7002, 0.9005)\n centers[24] = (0.9003, 0.9003)\n centers[25] = (0.3999, 0.3999)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9596919311655336} + visualization_path: + execution_time_mean: 0.29505715798586607 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..eb40faa510dfe807f333dc83898f4daee968a014 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9596919311655336, + "public": { + "centers_str": " centers[0] = (0.0991, 0.0991)\n centers[1] = (0.2985, 0.0954)\n centers[2] = (0.5014, 0.0953)\n centers[3] = (0.7007, 0.0990)\n centers[4] = (0.9004, 0.0996)\n centers[5] = (0.0954, 0.2985)\n centers[6] = (0.2816, 0.2816)\n centers[7] = (0.5182, 0.2815)\n centers[8] = (0.7044, 0.2984)\n centers[9] = (0.9006, 0.2998)\n centers[10] = (0.0953, 0.5014)\n centers[11] = (0.2815, 0.5182)\n centers[12] = (0.5182, 0.5182)\n centers[13] = (0.7044, 0.5014)\n centers[14] = (0.9006, 0.5000)\n centers[15] = (0.0990, 0.7007)\n centers[16] = (0.2984, 0.7044)\n centers[17] = (0.5014, 0.7044)\n centers[18] = (0.7008, 0.7008)\n centers[19] = (0.9005, 0.7002)\n centers[20] = (0.0996, 0.9004)\n centers[21] = (0.2998, 0.9006)\n centers[22] = (0.5000, 0.9006)\n centers[23] = (0.7002, 0.9005)\n centers[24] = (0.9003, 0.9003)\n centers[25] = (0.3999, 0.3999)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9596919311655336 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_46/results/packing_viz.png", + "execution_time_mean": 0.29505715798586607, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..45cb0a541ad2f1d6ea517fb0ae730643dcb19411 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..e09c22ed00d77ca5c5f978b31f16a3014de386f0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/edit.diff @@ -0,0 +1,165 @@ +--- a/original.py ++++ b/original.py +@@ -1,126 +1,155 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a Gaussian repulsion to create a central void. + # This method, inspired by a successful prior program, pushes circles + # away from a central point to make space for the 26th circle. This + # allows for a more global and efficient rearrangement of the packing. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 # Tuned displacement magnitude + sigma = 0.15 # Range of the repulsive force + + grid_centers = centers[:25].copy() + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + centers[:25] = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the 26th circle in the center of the created void. + centers[25] = void_center + +- # Safeguard: clip centers to stay within the unit square. +- centers = np.clip(centers, 0.0001, 0.9999) ++ # Safeguard: clip centers to stay within a margin of the unit square for stability. ++ centers = np.clip(centers, 0.01, 0.99) + +- # Compute maximum valid radii for this improved configuration ++ # 4. Relax the center positions using a force-directed approach with annealing. ++ # This allows circles to settle into a more stable configuration. ++ num_relax_iterations = 150 ++ for iter_idx in range(num_relax_iterations): ++ # Annealing schedule: start with larger steps/forces, then refine. ++ progress = iter_idx / (num_relax_iterations - 1) if num_relax_iterations > 1 else 1 ++ step_size = 0.01 * (1 - progress) + 0.001 * progress ++ repulsion_strength = 1e-4 * (1 - progress) + 2e-5 * progress ++ boundary_strength = 2e-4 ++ ++ forces = np.zeros_like(centers) ++ for i in range(n): ++ # Inter-circle repulsion force ++ for j in range(n): ++ if i == j: ++ continue ++ dist_vec = centers[i] - centers[j] ++ dist = np.linalg.norm(dist_vec) ++ if dist > 1e-7: ++ forces[i] += (dist_vec / dist) * (repulsion_strength / dist**2) ++ ++ # Boundary repulsion force ++ forces[i, 0] += boundary_strength / centers[i, 0]**2 ++ forces[i, 0] -= boundary_strength / (1 - centers[i, 0])**2 ++ forces[i, 1] += boundary_strength / centers[i, 1]**2 ++ forces[i, 1] -= boundary_strength / (1 - centers[i, 1])**2 ++ ++ # Update positions and clamp ++ centers += forces * step_size ++ centers = np.clip(centers, 0.01, 0.99) ++ ++ # Compute maximum valid radii for this relaxed configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + +- # First, limit by distance to square borders +- for i in range(n): +- x, y = centers[i] +- radii[i] = min(x, y, 1 - x, 1 - y) ++ # First, limit by distance to square borders (vectorized for efficiency) ++ radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/main.py new file mode 100644 index 0000000000000000000000000000000000000000..f8886910ee211aa8213bee924b4654a06e8f9682 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/main.py @@ -0,0 +1,155 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a Gaussian repulsion to create a central void. + # This method, inspired by a successful prior program, pushes circles + # away from a central point to make space for the 26th circle. This + # allows for a more global and efficient rearrangement of the packing. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 # Tuned displacement magnitude + sigma = 0.15 # Range of the repulsive force + + grid_centers = centers[:25].copy() + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + centers[:25] = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Safeguard: clip centers to stay within a margin of the unit square for stability. + centers = np.clip(centers, 0.01, 0.99) + + # 4. Relax the center positions using a force-directed approach with annealing. + # This allows circles to settle into a more stable configuration. + num_relax_iterations = 150 + for iter_idx in range(num_relax_iterations): + # Annealing schedule: start with larger steps/forces, then refine. + progress = iter_idx / (num_relax_iterations - 1) if num_relax_iterations > 1 else 1 + step_size = 0.01 * (1 - progress) + 0.001 * progress + repulsion_strength = 1e-4 * (1 - progress) + 2e-5 * progress + boundary_strength = 2e-4 + + forces = np.zeros_like(centers) + for i in range(n): + # Inter-circle repulsion force + for j in range(n): + if i == j: + continue + dist_vec = centers[i] - centers[j] + dist = np.linalg.norm(dist_vec) + if dist > 1e-7: + forces[i] += (dist_vec / dist) * (repulsion_strength / dist**2) + + # Boundary repulsion force + forces[i, 0] += boundary_strength / centers[i, 0]**2 + forces[i, 0] -= boundary_strength / (1 - centers[i, 0])**2 + forces[i, 1] += boundary_strength / centers[i, 1]**2 + forces[i, 1] -= boundary_strength / (1 - centers[i, 1])**2 + + # Update positions and clamp + centers += forces * step_size + centers = np.clip(centers, 0.01, 0.99) + + # Compute maximum valid radii for this relaxed configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/original.py new file mode 100644 index 0000000000000000000000000000000000000000..c6cb8006b0ac625a7315d0a2cf4159eb339533ea --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/original.py @@ -0,0 +1,126 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a Gaussian repulsion to create a central void. + # This method, inspired by a successful prior program, pushes circles + # away from a central point to make space for the 26th circle. This + # allows for a more global and efficient rearrangement of the packing. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 # Tuned displacement magnitude + sigma = 0.15 # Range of the repulsive force + + grid_centers = centers[:25].copy() + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + centers[:25] = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Safeguard: clip centers to stay within the unit square. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..2f59bccb5b763f81aba868cd40a73b2fa8ca3cc6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_47/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_47/results +Run 1/1 completed in 0.59 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.8560842949834977 + public: {'centers_str': ' centers[0] = (0.1101, 0.1101)\n centers[1] = (0.2988, 0.1063)\n centers[2] = (0.5014, 0.1061)\n centers[3] = (0.7006, 0.1093)\n centers[4] = (0.8894, 0.1106)\n centers[5] = (0.1063, 0.2988)\n centers[6] = (0.2805, 0.2805)\n centers[7] = (0.5196, 0.2803)\n centers[8] = (0.7049, 0.2985)\n centers[9] = (0.8904, 0.3002)\n centers[10] = (0.1061, 0.5014)\n centers[11] = (0.2803, 0.5196)\n centers[12] = (0.5196, 0.5196)\n centers[13] = (0.7050, 0.5014)\n centers[14] = (0.8905, 0.5001)\n centers[15] = (0.1093, 0.7006)\n centers[16] = (0.2985, 0.7049)\n centers[17] = (0.5014, 0.7050)\n centers[18] = (0.7009, 0.7009)\n centers[19] = (0.8902, 0.6999)\n centers[20] = (0.1106, 0.8894)\n centers[21] = (0.3002, 0.8904)\n centers[22] = (0.5001, 0.8905)\n centers[23] = (0.6999, 0.8902)\n centers[24] = (0.8893, 0.8893)\n centers[25] = (0.3998, 0.3998)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.8560842949834977} + visualization_path: + execution_time_mean: 0.5916333459317684 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..9e5507102e497d08031c5c0a22a96e91209b6055 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.8560842949834977, + "public": { + "centers_str": " centers[0] = (0.1101, 0.1101)\n centers[1] = (0.2988, 0.1063)\n centers[2] = (0.5014, 0.1061)\n centers[3] = (0.7006, 0.1093)\n centers[4] = (0.8894, 0.1106)\n centers[5] = (0.1063, 0.2988)\n centers[6] = (0.2805, 0.2805)\n centers[7] = (0.5196, 0.2803)\n centers[8] = (0.7049, 0.2985)\n centers[9] = (0.8904, 0.3002)\n centers[10] = (0.1061, 0.5014)\n centers[11] = (0.2803, 0.5196)\n centers[12] = (0.5196, 0.5196)\n centers[13] = (0.7050, 0.5014)\n centers[14] = (0.8905, 0.5001)\n centers[15] = (0.1093, 0.7006)\n centers[16] = (0.2985, 0.7049)\n centers[17] = (0.5014, 0.7050)\n centers[18] = (0.7009, 0.7009)\n centers[19] = (0.8902, 0.6999)\n centers[20] = (0.1106, 0.8894)\n centers[21] = (0.3002, 0.8904)\n centers[22] = (0.5001, 0.8905)\n centers[23] = (0.6999, 0.8902)\n centers[24] = (0.8893, 0.8893)\n centers[25] = (0.3998, 0.3998)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.8560842949834977 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_47/results/packing_viz.png", + "execution_time_mean": 0.5916333459317684, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6e762d90bcbf47c53905435332a24bd403f8b7c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_47/search_replace.txt @@ -0,0 +1,93 @@ +Based on my analysis of the visualization and my expertise in computational geometry, the current arrangement is a high-energy, "frozen" state. The Gaussian deformation successfully creates a central void, but it does so at the cost of severely compressing the four nearest circles, making them inefficiently small. The key to a better packing is to allow the system to relax and self-organize into a lower-energy configuration. + +My proposed edit introduces a force-directed relaxation phase. This post-processing step simulates repulsive forces between all circles and the container walls, allowing the circles to naturally spread out and find more optimal positions. This will specifically help the small, squashed circles to move into larger spaces and grow, thus increasing the total sum of radii. To make this simulation numerically stable, I am also increasing the margin from the boundaries. + +### Edit 1 + + +add_force_relaxation_with_margin + + + +The visualization shows a suboptimal configuration because the static placement creates high stress, particularly for the circles near the center, which become extremely small. This edit introduces a force-directed relaxation phase to allow the circles to settle into a more efficient, lower-energy packing. + +To ensure numerical stability of the boundary repulsion forces (`~1/distance^2`), I first increase the margin from the edge by changing the clipping range from `[0.0001, 0.9999]` to `[0.01, 0.99]`. This prevents forces from becoming astronomically large. + +The core of the change is an iterative relaxation loop that runs for 150 steps: +1. **Repulsion Forces:** All circles repel each other to create space. +2. **Boundary Forces:** Strong repulsion from the walls keeps the packing contained. +3. **Annealing Schedule:** The simulation starts with a large step size and strong forces to quickly rearrange the packing, then gradually reduces them to fine-tune the final positions. + +This process allows the entire system to self-organize, enabling the previously squashed circles to expand and leading to a better overall sum of radii. + + + +<<<<<<< SEARCH + # Safeguard: clip centers to stay within the unit square. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii +======= + # Safeguard: clip centers to stay within a margin of the unit square for stability. + centers = np.clip(centers, 0.01, 0.99) + + # 4. Relax the center positions using a force-directed approach with annealing. + # This allows circles to settle into a more stable configuration. + num_relax_iterations = 150 + for iter_idx in range(num_relax_iterations): + # Annealing schedule: start with larger steps/forces, then refine. + progress = iter_idx / (num_relax_iterations - 1) if num_relax_iterations > 1 else 1 + step_size = 0.01 * (1 - progress) + 0.001 * progress + repulsion_strength = 1e-4 * (1 - progress) + 2e-5 * progress + boundary_strength = 2e-4 + + forces = np.zeros_like(centers) + for i in range(n): + # Inter-circle repulsion force + for j in range(n): + if i == j: + continue + dist_vec = centers[i] - centers[j] + dist = np.linalg.norm(dist_vec) + if dist > 1e-7: + forces[i] += (dist_vec / dist) * (repulsion_strength / dist**2) + + # Boundary repulsion force + forces[i, 0] += boundary_strength / centers[i, 0]**2 + forces[i, 0] -= boundary_strength / (1 - centers[i, 0])**2 + forces[i, 1] += boundary_strength / centers[i, 1]**2 + forces[i, 1] -= boundary_strength / (1 - centers[i, 1])**2 + + # Update positions and clamp + centers += forces * step_size + centers = np.clip(centers, 0.01, 0.99) + + # Compute maximum valid radii for this relaxed configuration + radii = compute_max_radii(centers) + return centers, radii +>>>>>>> REPLACE + + +### Edit 2 + + +vectorize_radius_initialization + + + +This is a minor code quality improvement in the `compute_max_radii` function. The initial calculation of each circle's maximum possible radius (based on its distance to the four boundaries) was performed in a loop. I am replacing this loop with a single, equivalent NumPy vectorized operation. This is more idiomatic, readable, and computationally efficient, although the performance impact for N=26 is negligible. It does not change the logic. + + + +<<<<<<< SEARCH + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) +======= + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab79269dd3023f471517a5137f5afecb510aa79a Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..e008870dc8c9b8a9dd831adb1e4d6e10234cabe2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_48/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_48/results +Run 1/1 completed in 0.47 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9616585149454673 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2987, 0.0959)\n centers[2] = (0.5013, 0.0959)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0960, 0.2987)\n centers[6] = (0.2819, 0.2819)\n centers[7] = (0.5181, 0.2819)\n centers[8] = (0.7040, 0.2987)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0959, 0.5013)\n centers[11] = (0.2819, 0.5181)\n centers[12] = (0.5181, 0.5181)\n centers[13] = (0.7040, 0.5013)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2987, 0.7040)\n centers[17] = (0.5013, 0.7040)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9616585149454673} + visualization_path: + execution_time_mean: 0.4711709739640355 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..8ef3cb1e44d392fab6c74bd1e01acb43879949ea --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9616585149454673, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2987, 0.0959)\n centers[2] = (0.5013, 0.0959)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0960, 0.2987)\n centers[6] = (0.2819, 0.2819)\n centers[7] = (0.5181, 0.2819)\n centers[8] = (0.7040, 0.2987)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0959, 0.5013)\n centers[11] = (0.2819, 0.5181)\n centers[12] = (0.5181, 0.5181)\n centers[13] = (0.7040, 0.5013)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2987, 0.7040)\n centers[17] = (0.5013, 0.7040)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9616585149454673 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_48/results/packing_viz.png", + "execution_time_mean": 0.4711709739640355, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac0f6176e8c9e3eaa1d0ad589c209a694dc76fc3 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..6eb60871f8ef138896846f51fb6fa7e6efc4319b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_5/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_5/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.6185888047441324 + public: {'centers_str': ' centers[0] = (0.1000, 0.0833)\n centers[1] = (0.3000, 0.0833)\n centers[2] = (0.5000, 0.0833)\n centers[3] = (0.7000, 0.0833)\n centers[4] = (0.9000, 0.0833)\n centers[5] = (0.2000, 0.2500)\n centers[6] = (0.4000, 0.2500)\n centers[7] = (0.6000, 0.2500)\n centers[8] = (0.8000, 0.2500)\n centers[9] = (0.1000, 0.4167)\n centers[10] = (0.3000, 0.4167)\n centers[11] = (0.5000, 0.4167)\n centers[12] = (0.7000, 0.4167)\n centers[13] = (0.9000, 0.4167)\n centers[14] = (0.2000, 0.5833)\n centers[15] = (0.4000, 0.5833)\n centers[16] = (0.6000, 0.5833)\n centers[17] = (0.8000, 0.5833)\n centers[18] = (0.1000, 0.7500)\n centers[19] = (0.3000, 0.7500)\n centers[20] = (0.5000, 0.7500)\n centers[21] = (0.7000, 0.7500)\n centers[22] = (0.9000, 0.7500)\n centers[23] = (0.3000, 0.9167)\n centers[24] = (0.5000, 0.9167)\n centers[25] = (0.7000, 0.9167)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.6185888047441324} + visualization_path: + execution_time_mean: 0.002053783740848303 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..dad2b6fbdd2661131e7fa22cf5fdf8b98a37be79 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.6185888047441324, + "public": { + "centers_str": " centers[0] = (0.1000, 0.0833)\n centers[1] = (0.3000, 0.0833)\n centers[2] = (0.5000, 0.0833)\n centers[3] = (0.7000, 0.0833)\n centers[4] = (0.9000, 0.0833)\n centers[5] = (0.2000, 0.2500)\n centers[6] = (0.4000, 0.2500)\n centers[7] = (0.6000, 0.2500)\n centers[8] = (0.8000, 0.2500)\n centers[9] = (0.1000, 0.4167)\n centers[10] = (0.3000, 0.4167)\n centers[11] = (0.5000, 0.4167)\n centers[12] = (0.7000, 0.4167)\n centers[13] = (0.9000, 0.4167)\n centers[14] = (0.2000, 0.5833)\n centers[15] = (0.4000, 0.5833)\n centers[16] = (0.6000, 0.5833)\n centers[17] = (0.8000, 0.5833)\n centers[18] = (0.1000, 0.7500)\n centers[19] = (0.3000, 0.7500)\n centers[20] = (0.5000, 0.7500)\n centers[21] = (0.7000, 0.7500)\n centers[22] = (0.9000, 0.7500)\n centers[23] = (0.3000, 0.9167)\n centers[24] = (0.5000, 0.9167)\n centers[25] = (0.7000, 0.9167)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.6185888047441324 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_5/results/packing_viz.png", + "execution_time_mean": 0.002053783740848303, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c93e2116efab96c69626a7a305702168dafd3b29 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..532a184ac05b691e218af70a296a60241c8442c8 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": false, + "error": "name 'np' is not defined" +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..e532bc7319296f3763e3eea3ad7fddfbe74e2838 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/job_log.out @@ -0,0 +1,14 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_51/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_51/results +Evaluation error: name 'np' is not defined +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/metrics.json +Evaluation or Validation failed: name 'np' is not defined +Metrics: + combined_score: 0.0 + execution_time_mean: 0.0 + execution_time_std: 0.0 + num_successful_runs: 0 + num_valid_runs: 0 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..fec2021a6a036637c9d3049ae9778c77cef78421 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_51/results/metrics.json @@ -0,0 +1,9 @@ +{ + "combined_score": 0.0, + "execution_time_mean": 0.0, + "execution_time_std": 0.0, + "num_successful_runs": 0, + "num_valid_runs": 0, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3987c35bf33ba11698fa6eb13b82494c6713262a Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..64649e9c1a85b56aba0c6e2090c2cbf5a7a10db6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/edit.diff @@ -0,0 +1,212 @@ +--- a/original.py ++++ b/original.py +@@ -1,204 +1,206 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + # A small epsilon for floating point comparisons to avoid issues with exact equality or near-zero values. + EPSILON = 1e-12 # Using a smaller epsilon for higher precision in radius calculations and general robustness + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + radii[i] = max(radii[i], EPSILON) # Ensure a small positive radius to prevent division by zero later + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + # The proportional scaling mechanism is efficient in reducing overlaps. + for _ in range(500): # Fixed number of iterations for robustness (from Inspiration 4) + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + # Using EPSILON here for precision (from Inspiration 4) + if radii[i] + radii[j] > dist + EPSILON: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + + # Avoid division by zero if radii are extremely small (from Inspiration 4) + if sum_r < EPSILON: + radii[i] = 0.0 # Set to zero if they are effectively non-existent + radii[j] = 0.0 + changed_in_pass = True # Mark as changed to continue iterations + continue + + scale = dist / sum_r + + # Apply scaling. Only mark as changed if actual reduction happens (from Inspiration 4) + if scale < 1.0 - EPSILON: # Check for a meaningful reduction + radii[i] *= scale + radii[j] *= scale + changed_in_pass = True + + # If a full pass resulted in no significant changes, the packing is stable. + if not changed_in_pass: + break + + # Final check to ensure radii are non-negative and respect boundary limits (from Inspiration 4) + for i in range(n): + x, y = centers[i] + boundary_r = min(x, 1 - x, y, 1 - y) + radii[i] = max(0.0, min(radii[i], boundary_r)) + + return radii + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by initially placing + them in a deformed grid and then iteratively refining their positions + using a two-stage adaptive force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Place the 26th circle in a central interstitial void (0.4, 0.4). +- void_center = np.array([0.4, 0.4]) # Keeping this as a good starting point ++ # 2. Place the 26th circle in a central interstitial void. ++ # Shifting to (0.5, 0.5) for improved symmetry and balanced initial distribution. ++ void_center = np.array([0.5, 0.5]) + + # 3. Apply a Gaussian deformation to the 25 grid circles. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push based on prior successful runs: +- amplitude = 0.045 # Slightly increased amplitude for more initial separation than previous 0.04 or 0.042 ++ # Increased amplitude for a stronger initial push from the void center, making more room. ++ amplitude = 0.05 + sigma = 0.15 # Spread of the Gaussian, defines influence range + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + if np.linalg.norm(pos_vector) > EPSILON: # Use EPSILON for robustness + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Ensure centers remain strictly within bounds, using EPSILON + + # 4. Two-Stage Adaptive Force-Directed Relaxation. (Re-introduced from Inspiration 1-3, with tuning) + + # Shared parameters for both stages: + repulsion_threshold = 0.205 # Increased from 0.185 to encourage tighter packing before repelling + boundary_margin = 0.035 # Decreased from 0.04 to allow circles closer to boundary + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 150 # Increased iterations for broader exploration + exploration_step_size = 0.003 # Slightly increased step size + exploration_repulsion_strength = 0.02 # Increased repulsion strength + exploration_boundary_strength = 0.1 # Increased boundary repulsion strength + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + # Apply repulsion if distance is less than threshold + if 0 < dist < repulsion_threshold: + # Force inversely proportional to distance, stronger when closer + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + # Use stronger force near boundaries + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Clip using EPSILON + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 200 # Increased iterations for finer convergence + refinement_step_size = 0.001 # Slightly increased step size + refinement_repulsion_strength = 0.008 # Slightly increased repulsion + refinement_boundary_strength = 0.04 # Slightly increased boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Clip using EPSILON + + # 5. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/main.py new file mode 100644 index 0000000000000000000000000000000000000000..fefdd9948012320eab3b1ea12007c74d3244468b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/main.py @@ -0,0 +1,206 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +# A small epsilon for floating point comparisons to avoid issues with exact equality or near-zero values. +EPSILON = 1e-12 # Using a smaller epsilon for higher precision in radius calculations and general robustness + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + radii[i] = max(radii[i], EPSILON) # Ensure a small positive radius to prevent division by zero later + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + # The proportional scaling mechanism is efficient in reducing overlaps. + for _ in range(500): # Fixed number of iterations for robustness (from Inspiration 4) + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + # Using EPSILON here for precision (from Inspiration 4) + if radii[i] + radii[j] > dist + EPSILON: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + + # Avoid division by zero if radii are extremely small (from Inspiration 4) + if sum_r < EPSILON: + radii[i] = 0.0 # Set to zero if they are effectively non-existent + radii[j] = 0.0 + changed_in_pass = True # Mark as changed to continue iterations + continue + + scale = dist / sum_r + + # Apply scaling. Only mark as changed if actual reduction happens (from Inspiration 4) + if scale < 1.0 - EPSILON: # Check for a meaningful reduction + radii[i] *= scale + radii[j] *= scale + changed_in_pass = True + + # If a full pass resulted in no significant changes, the packing is stable. + if not changed_in_pass: + break + + # Final check to ensure radii are non-negative and respect boundary limits (from Inspiration 4) + for i in range(n): + x, y = centers[i] + boundary_r = min(x, 1 - x, y, 1 - y) + radii[i] = max(0.0, min(radii[i], boundary_r)) + + return radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by initially placing + them in a deformed grid and then iteratively refining their positions + using a two-stage adaptive force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a central interstitial void. + # Shifting to (0.5, 0.5) for improved symmetry and balanced initial distribution. + void_center = np.array([0.5, 0.5]) + + # 3. Apply a Gaussian deformation to the 25 grid circles. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push based on prior successful runs: + # Increased amplitude for a stronger initial push from the void center, making more room. + amplitude = 0.05 + sigma = 0.15 # Spread of the Gaussian, defines influence range + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + if np.linalg.norm(pos_vector) > EPSILON: # Use EPSILON for robustness + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Ensure centers remain strictly within bounds, using EPSILON + + # 4. Two-Stage Adaptive Force-Directed Relaxation. (Re-introduced from Inspiration 1-3, with tuning) + + # Shared parameters for both stages: + repulsion_threshold = 0.205 # Increased from 0.185 to encourage tighter packing before repelling + boundary_margin = 0.035 # Decreased from 0.04 to allow circles closer to boundary + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 150 # Increased iterations for broader exploration + exploration_step_size = 0.003 # Slightly increased step size + exploration_repulsion_strength = 0.02 # Increased repulsion strength + exploration_boundary_strength = 0.1 # Increased boundary repulsion strength + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + # Apply repulsion if distance is less than threshold + if 0 < dist < repulsion_threshold: + # Force inversely proportional to distance, stronger when closer + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + # Use stronger force near boundaries + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Clip using EPSILON + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 200 # Increased iterations for finer convergence + refinement_step_size = 0.001 # Slightly increased step size + refinement_repulsion_strength = 0.008 # Slightly increased repulsion + refinement_boundary_strength = 0.04 # Slightly increased boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Clip using EPSILON + + # 5. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/original.py new file mode 100644 index 0000000000000000000000000000000000000000..05bb8be4de53e8e3e1296dac1c84e41a1c7edbe9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/original.py @@ -0,0 +1,204 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +# A small epsilon for floating point comparisons to avoid issues with exact equality or near-zero values. +EPSILON = 1e-12 # Using a smaller epsilon for higher precision in radius calculations and general robustness + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + radii[i] = max(radii[i], EPSILON) # Ensure a small positive radius to prevent division by zero later + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + # The proportional scaling mechanism is efficient in reducing overlaps. + for _ in range(500): # Fixed number of iterations for robustness (from Inspiration 4) + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + # Using EPSILON here for precision (from Inspiration 4) + if radii[i] + radii[j] > dist + EPSILON: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + + # Avoid division by zero if radii are extremely small (from Inspiration 4) + if sum_r < EPSILON: + radii[i] = 0.0 # Set to zero if they are effectively non-existent + radii[j] = 0.0 + changed_in_pass = True # Mark as changed to continue iterations + continue + + scale = dist / sum_r + + # Apply scaling. Only mark as changed if actual reduction happens (from Inspiration 4) + if scale < 1.0 - EPSILON: # Check for a meaningful reduction + radii[i] *= scale + radii[j] *= scale + changed_in_pass = True + + # If a full pass resulted in no significant changes, the packing is stable. + if not changed_in_pass: + break + + # Final check to ensure radii are non-negative and respect boundary limits (from Inspiration 4) + for i in range(n): + x, y = centers[i] + boundary_r = min(x, 1 - x, y, 1 - y) + radii[i] = max(0.0, min(radii[i], boundary_r)) + + return radii + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by initially placing + them in a deformed grid and then iteratively refining their positions + using a two-stage adaptive force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a central interstitial void (0.4, 0.4). + void_center = np.array([0.4, 0.4]) # Keeping this as a good starting point + + # 3. Apply a Gaussian deformation to the 25 grid circles. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push based on prior successful runs: + amplitude = 0.045 # Slightly increased amplitude for more initial separation than previous 0.04 or 0.042 + sigma = 0.15 # Spread of the Gaussian, defines influence range + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + if np.linalg.norm(pos_vector) > EPSILON: # Use EPSILON for robustness + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Ensure centers remain strictly within bounds, using EPSILON + + # 4. Two-Stage Adaptive Force-Directed Relaxation. (Re-introduced from Inspiration 1-3, with tuning) + + # Shared parameters for both stages: + repulsion_threshold = 0.205 # Increased from 0.185 to encourage tighter packing before repelling + boundary_margin = 0.035 # Decreased from 0.04 to allow circles closer to boundary + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 150 # Increased iterations for broader exploration + exploration_step_size = 0.003 # Slightly increased step size + exploration_repulsion_strength = 0.02 # Increased repulsion strength + exploration_boundary_strength = 0.1 # Increased boundary repulsion strength + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + # Apply repulsion if distance is less than threshold + if 0 < dist < repulsion_threshold: + # Force inversely proportional to distance, stronger when closer + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + # Use stronger force near boundaries + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Clip using EPSILON + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 200 # Increased iterations for finer convergence + refinement_step_size = 0.001 # Slightly increased step size + refinement_repulsion_strength = 0.008 # Slightly increased repulsion + refinement_boundary_strength = 0.04 # Slightly increased boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, EPSILON, 1.0 - EPSILON) # Clip using EPSILON + + # 5. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..590cf0f0f960c71fa3c52532451f61adb334ee83 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_52/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_52/results +Run 1/1 completed in 0.49 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.76431690635172 + public: {'centers_str': ' centers[0] = (0.0997, 0.0997)\n centers[1] = (0.2998, 0.0989)\n centers[2] = (0.5000, 0.0972)\n centers[3] = (0.7002, 0.0989)\n centers[4] = (0.9003, 0.0997)\n centers[5] = (0.0989, 0.2998)\n centers[6] = (0.2945, 0.2945)\n centers[7] = (0.5000, 0.2808)\n centers[8] = (0.7055, 0.2945)\n centers[9] = (0.9011, 0.2998)\n centers[10] = (0.0972, 0.5000)\n centers[11] = (0.2808, 0.5000)\n centers[12] = (0.5000, 0.5000)\n centers[13] = (0.7192, 0.5000)\n centers[14] = (0.9028, 0.5000)\n centers[15] = (0.0989, 0.7002)\n centers[16] = (0.2945, 0.7055)\n centers[17] = (0.5000, 0.7192)\n centers[18] = (0.7055, 0.7055)\n centers[19] = (0.9011, 0.7002)\n centers[20] = (0.0997, 0.9003)\n centers[21] = (0.2998, 0.9011)\n centers[22] = (0.5000, 0.9028)\n centers[23] = (0.7002, 0.9011)\n centers[24] = (0.9003, 0.9003)\n centers[25] = (0.5000, 0.5000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.76431690635172} + visualization_path: + execution_time_mean: 0.48836695216596127 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..0a037ee32bfebc34011f419e9c20f9dfc3d3dbaf --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.76431690635172, + "public": { + "centers_str": " centers[0] = (0.0997, 0.0997)\n centers[1] = (0.2998, 0.0989)\n centers[2] = (0.5000, 0.0972)\n centers[3] = (0.7002, 0.0989)\n centers[4] = (0.9003, 0.0997)\n centers[5] = (0.0989, 0.2998)\n centers[6] = (0.2945, 0.2945)\n centers[7] = (0.5000, 0.2808)\n centers[8] = (0.7055, 0.2945)\n centers[9] = (0.9011, 0.2998)\n centers[10] = (0.0972, 0.5000)\n centers[11] = (0.2808, 0.5000)\n centers[12] = (0.5000, 0.5000)\n centers[13] = (0.7192, 0.5000)\n centers[14] = (0.9028, 0.5000)\n centers[15] = (0.0989, 0.7002)\n centers[16] = (0.2945, 0.7055)\n centers[17] = (0.5000, 0.7192)\n centers[18] = (0.7055, 0.7055)\n centers[19] = (0.9011, 0.7002)\n centers[20] = (0.0997, 0.9003)\n centers[21] = (0.2998, 0.9011)\n centers[22] = (0.5000, 0.9028)\n centers[23] = (0.7002, 0.9011)\n centers[24] = (0.9003, 0.9003)\n centers[25] = (0.5000, 0.5000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.76431690635172 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_52/results/packing_viz.png", + "execution_time_mean": 0.48836695216596127, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d442c07c6536838efe98bd68bc339e7c50c1fe6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_52/search_replace.txt @@ -0,0 +1,34 @@ + +By analyzing the visualization, the current arrangement shows a large central circle at (0.4, 0.4) surrounded by several very small circles. This indicates an asymmetric void placement and a potentially imbalanced distribution of forces, leading to some circles being disproportionately small. + +To address this, I propose two changes: +1. **Shift `void_center` to `(0.5, 0.5)`**: Moving the central void to the exact center of the unit square will introduce greater symmetry to the initial setup. This should lead to a more balanced outward push on the surrounding grid circles and, consequently, a more uniform distribution of radii for the circles around the center. +2. **Increase Gaussian deformation `amplitude`**: To further ensure that the grid circles have enough initial space, I will slightly increase the `amplitude` of the Gaussian deformation from `0.045` to `0.05`. This will provide a stronger initial push, especially for circles closest to the void, allowing them to better accommodate the central 26th circle and grow larger themselves. + +These changes aim to improve the spatial distribution of circles, especially those around the central region, by leveraging symmetry and a more assertive initial separation, thus maximizing the overall sum of radii. + + +<<<<<<< SEARCH + # 2. Place the 26th circle in a central interstitial void (0.4, 0.4). + void_center = np.array([0.4, 0.4]) # Keeping this as a good starting point + + # 3. Apply a Gaussian deformation to the 25 grid circles. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push based on prior successful runs: + amplitude = 0.045 # Slightly increased amplitude for more initial separation than previous 0.04 or 0.042 + sigma = 0.15 # Spread of the Gaussian, defines influence range +======= + # 2. Place the 26th circle in a central interstitial void. + # Shifting to (0.5, 0.5) for improved symmetry and balanced initial distribution. + void_center = np.array([0.5, 0.5]) + + # 3. Apply a Gaussian deformation to the 25 grid circles. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push based on prior successful runs: + # Increased amplitude for a stronger initial push from the void center, making more room. + amplitude = 0.05 + sigma = 0.15 # Spread of the Gaussian, defines influence range +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..69b162931c9aa734006cbb1263ff523b9a5ac7cd Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..a6c4096ea5153a99e1a55b0119b53f95aeaf7998 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/edit.diff @@ -0,0 +1,212 @@ +--- a/original.py ++++ b/original.py +@@ -1,161 +1,171 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid +- to create a larger void for the 26th circle. ++ and applying a two-stage (exploration/refinement) force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. +- # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. +- # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + +- # Hyperparameters for the Gaussian push: +- amplitude = 0.04 # The maximum distance to push a circle. +- sigma = 0.15 # The "spread" of the push, controlling its influence range. ++ # Increased amplitude to create a larger initial void. ++ amplitude = 0.05 ++ sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) +- +- # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) +- +- # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + +- # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center +- +- # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + +- # 5. Iteratively refine positions for all 26 circles after the initial deformation. +- # This allows all circles, including the 26th, to find more optimal positions +- # through mutual repulsion and boundary interactions. +- refinement_iters = 50 # Number of refinement steps. +- refinement_step_size = 0.001 # Gentle step size for fine-tuning. +- refinement_repulsion_strength = 0.01 # Weaker repulsion for fine-tuning. +- refinement_boundary_strength = 0.05 # Weaker boundary repulsion. +- refinement_repulsion_threshold = 0.18 # Encourages slightly tighter packing. +- refinement_boundary_margin = 0.05 # Standard margin for boundary checks. ++ # 4. Stage 1: High-Energy Exploration ++ # This stage uses strong forces and a large step size to break the initial ++ # grid structure and find a better global arrangement. ++ exploration_iters = 250 ++ exploration_step_size = 0.003 ++ exploration_repulsion_strength = 0.02 ++ exploration_boundary_strength = 0.1 ++ repulsion_threshold = 0.20 # Increased threshold to encourage movement ++ boundary_margin = 0.04 # Smaller margin to better utilize edges + +- for _ in range(refinement_iters): ++ for _ in range(exploration_iters): + forces = np.zeros_like(centers) +- +- # a. Calculate circle-circle repulsion forces. + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- +- if 0 < dist < refinement_repulsion_threshold: +- force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist +- force_vec = force_magnitude * (vec / dist) ++ if 0 < dist < repulsion_threshold: ++ force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec +- +- # b. Calculate boundary repulsion forces. + for i in range(n): + x, y = centers[i] +- if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) +- if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) +- if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) +- if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) ++ if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) ++ centers += exploration_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) + +- # c. Update center positions. ++ # 5. Stage 2: Low-Energy Refinement ++ # This stage uses more iterations with weaker forces and a smaller step size ++ # to fine-tune the circle positions and settle into a dense local optimum. ++ refinement_iters = 400 ++ refinement_step_size = 0.0005 ++ refinement_repulsion_strength = 0.008 ++ refinement_boundary_strength = 0.04 ++ ++ for _ in range(refinement_iters): ++ forces = np.zeros_like(centers) ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_mag = refinement_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_mag * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces +- +- # d. Clip centers. + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/main.py new file mode 100644 index 0000000000000000000000000000000000000000..cd2a1c594f5f62160d5dedc59030456cbcbc0e88 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/main.py @@ -0,0 +1,171 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + and applying a two-stage (exploration/refinement) force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.05 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to break the initial + # grid structure and find a better global arrangement. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + repulsion_threshold = 0.20 # Increased threshold to encourage movement + boundary_margin = 0.04 # Smaller margin to better utilize edges + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to fine-tune the circle positions and settle into a dense local optimum. + refinement_iters = 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/original.py new file mode 100644 index 0000000000000000000000000000000000000000..b7006c696ca01e602dd712c6f075ecd95d8b6118 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/original.py @@ -0,0 +1,161 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.04 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Iteratively refine positions for all 26 circles after the initial deformation. + # This allows all circles, including the 26th, to find more optimal positions + # through mutual repulsion and boundary interactions. + refinement_iters = 50 # Number of refinement steps. + refinement_step_size = 0.001 # Gentle step size for fine-tuning. + refinement_repulsion_strength = 0.01 # Weaker repulsion for fine-tuning. + refinement_boundary_strength = 0.05 # Weaker boundary repulsion. + refinement_repulsion_threshold = 0.18 # Encourages slightly tighter packing. + refinement_boundary_margin = 0.05 # Standard margin for boundary checks. + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # a. Calculate circle-circle repulsion forces. + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # b. Calculate boundary repulsion forces. + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + # c. Update center positions. + centers += refinement_step_size * forces + + # d. Clip centers. + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..2f9681a9dc4ea8a8d8be35d6ab113a69fa77da5a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_54/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_54/results +Run 1/1 completed in 0.79 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.967515968945233 + public: {'centers_str': ' centers[0] = (0.0993, 0.0993)\n centers[1] = (0.2985, 0.0934)\n centers[2] = (0.5015, 0.0934)\n centers[3] = (0.7007, 0.0993)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0934, 0.2985)\n centers[6] = (0.2768, 0.2768)\n centers[7] = (0.5232, 0.2768)\n centers[8] = (0.7061, 0.2985)\n centers[9] = (0.9006, 0.3000)\n centers[10] = (0.0934, 0.5015)\n centers[11] = (0.2768, 0.5232)\n centers[12] = (0.5232, 0.5232)\n centers[13] = (0.7061, 0.5015)\n centers[14] = (0.9006, 0.5000)\n centers[15] = (0.0993, 0.7007)\n centers[16] = (0.2985, 0.7061)\n centers[17] = (0.5015, 0.7061)\n centers[18] = (0.7007, 0.7007)\n centers[19] = (0.9001, 0.7000)\n centers[20] = (0.1000, 0.9001)\n centers[21] = (0.3000, 0.9006)\n centers[22] = (0.5000, 0.9006)\n centers[23] = (0.7000, 0.9001)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.967515968945233} + visualization_path: + execution_time_mean: 0.7883413713425398 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..6621dd5db153c54a8d4f9566826328db4c4bf7b7 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.967515968945233, + "public": { + "centers_str": " centers[0] = (0.0993, 0.0993)\n centers[1] = (0.2985, 0.0934)\n centers[2] = (0.5015, 0.0934)\n centers[3] = (0.7007, 0.0993)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0934, 0.2985)\n centers[6] = (0.2768, 0.2768)\n centers[7] = (0.5232, 0.2768)\n centers[8] = (0.7061, 0.2985)\n centers[9] = (0.9006, 0.3000)\n centers[10] = (0.0934, 0.5015)\n centers[11] = (0.2768, 0.5232)\n centers[12] = (0.5232, 0.5232)\n centers[13] = (0.7061, 0.5015)\n centers[14] = (0.9006, 0.5000)\n centers[15] = (0.0993, 0.7007)\n centers[16] = (0.2985, 0.7061)\n centers[17] = (0.5015, 0.7061)\n centers[18] = (0.7007, 0.7007)\n centers[19] = (0.9001, 0.7000)\n centers[20] = (0.1000, 0.9001)\n centers[21] = (0.3000, 0.9006)\n centers[22] = (0.5000, 0.9006)\n centers[23] = (0.7000, 0.9001)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.967515968945233 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_54/results/packing_viz.png", + "execution_time_mean": 0.7883413713425398, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..3180cef6fe8c051c4389918da2d7c1cf8fcfc002 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_54/rewrite.txt @@ -0,0 +1,162 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + and applying a two-stage (exploration/refinement) force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.05 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to break the initial + # grid structure and find a better global arrangement. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + repulsion_threshold = 0.20 # Increased threshold to encourage movement + boundary_margin = 0.04 # Smaller margin to better utilize edges + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to fine-tune the circle positions and settle into a dense local optimum. + refinement_iters = 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e2324a6a3ce9d05eb315b09d3c97c551de794c06 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..8916ed0c6c389aa24ea9f1dc135ba67c1a57ae9d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_55/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_55/results +Run 1/1 completed in 0.37 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9635652269686839 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9635652269686839} + visualization_path: + execution_time_mean: 0.36656786082312465 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..6d36382b7aa4a43a57980ab946be9c9297ecbe93 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9635652269686839, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9635652269686839 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_55/results/packing_viz.png", + "execution_time_mean": 0.36656786082312465, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..67383612f455998f6fd300ce11a32ca3479168d1 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..00b16fba27cf5c505aa2aa6e5d1eb1d22bdca86d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/edit.diff @@ -0,0 +1,202 @@ +--- a/original.py ++++ b/original.py +@@ -1,193 +1,197 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: +- amplitude = 0.042 # The maximum distance to push a circle. ++ # Reduced amplitude to create a slightly smaller initial void for the 26th circle, ++ # aiming for more balanced radii between the central circle and its neighbors. ++ amplitude = 0.035 + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: +- repulsion_threshold = 0.185 ++ # Increased repulsion threshold to encourage circles to spread out more evenly ++ # from a slightly greater distance, which can lead to larger radii overall. ++ repulsion_threshold = 0.19 + boundary_margin = 0.04 + n = centers.shape[0] + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/main.py new file mode 100644 index 0000000000000000000000000000000000000000..eefc172fbd44197a5ed41ef30022621059a75745 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/main.py @@ -0,0 +1,197 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + # Reduced amplitude to create a slightly smaller initial void for the 26th circle, + # aiming for more balanced radii between the central circle and its neighbors. + amplitude = 0.035 + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + # Increased repulsion threshold to encourage circles to spread out more evenly + # from a slightly greater distance, which can lead to larger radii overall. + repulsion_threshold = 0.19 + boundary_margin = 0.04 + n = centers.shape[0] + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/original.py new file mode 100644 index 0000000000000000000000000000000000000000..c3082cb83518797899c2cdebac2b193e20eddd1a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/original.py @@ -0,0 +1,193 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 + boundary_margin = 0.04 + n = centers.shape[0] + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..854987d570abe5320c2f6f72b457fd00eb17fb6e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_56/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_56/results +Run 1/1 completed in 0.40 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9583428318504592 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2988, 0.0964)\n centers[2] = (0.5012, 0.0964)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0964, 0.2988)\n centers[6] = (0.2837, 0.2837)\n centers[7] = (0.5163, 0.2837)\n centers[8] = (0.7036, 0.2988)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0964, 0.5012)\n centers[11] = (0.2837, 0.5163)\n centers[12] = (0.5163, 0.5163)\n centers[13] = (0.7036, 0.5012)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2988, 0.7036)\n centers[17] = (0.5012, 0.7036)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9583428318504592} + visualization_path: + execution_time_mean: 0.3955969149246812 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..b8c73b549b97b828bdad4ae4924458f0c0bf24e6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9583428318504592, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2988, 0.0964)\n centers[2] = (0.5012, 0.0964)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0964, 0.2988)\n centers[6] = (0.2837, 0.2837)\n centers[7] = (0.5163, 0.2837)\n centers[8] = (0.7036, 0.2988)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0964, 0.5012)\n centers[11] = (0.2837, 0.5163)\n centers[12] = (0.5163, 0.5163)\n centers[13] = (0.7036, 0.5012)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2988, 0.7036)\n centers[17] = (0.5012, 0.7036)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9583428318504592 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_56/results/packing_viz.png", + "execution_time_mean": 0.3955969149246812, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..7821b28c84409e83f50d8fdebb98022d98c09892 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_56/search_replace.txt @@ -0,0 +1,76 @@ +gaussian_amplitude_and_repulsion_threshold +Reduced the Gaussian deformation `amplitude` to create a slightly smaller initial void, which should encourage the central circle and its neighbors to have more balanced radii. Increased `repulsion_threshold` in relaxation stages to make circles repel from a slightly greater distance, aiming for a more even distribution of forces and radii across the packing. This addresses the visual observation that the central circle is too dominant and its neighbors are too small. + + +<<<<<<< SEARCH + # Hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 + boundary_margin = 0.04 + n = centers.shape[0] +======= + # Hyperparameters for the Gaussian push: + # Reduced amplitude to create a slightly smaller initial void for the 26th circle, + # aiming for more balanced radii between the central circle and its neighbors. + amplitude = 0.035 + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + # Increased repulsion threshold to encourage circles to spread out more evenly + # from a slightly greater distance, which can lead to larger radii overall. + repulsion_threshold = 0.19 + boundary_margin = 0.04 + n = centers.shape[0] +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2dcbd63ad0561f590d9a9264d3e4cbbf1ceddb44 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/main.py new file mode 100644 index 0000000000000000000000000000000000000000..14a7335cae04ef736e073b1b9e18ae4959eeab90 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/main.py @@ -0,0 +1,184 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.05 # The maximum distance to push a circle. Increased to create a larger void. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This approach uses a high-energy "exploration" phase to break symmetry + # and find a good general configuration, followed by a low-energy + # "refinement" phase to fine-tune the positions. + + # Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to quickly move circles + # out of the initial grid structure and explore new arrangements. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + repulsion_threshold = 0.19 # A common threshold for both stages + boundary_margin = 0.04 # Use a smaller margin to utilize edge space better + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.zeros(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/original.py new file mode 100644 index 0000000000000000000000000000000000000000..8758155929c84916648ad978650354bd4090fe2f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/original.py @@ -0,0 +1,160 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. Increased slightly to make more room. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Iteratively refine positions for all 26 circles after the initial deformation. + # This allows all circles, including the 26th, to find more optimal positions + # through mutual repulsion and boundary interactions. + refinement_iters = 80 # Number of refinement steps. Increased for more thorough relaxation. + refinement_step_size = 0.002 # Step size for center adjustments. + refinement_repulsion_strength = 0.02 # Multiplier for circle-circle repulsion force. + refinement_boundary_strength = 0.1 # Multiplier for wall-repulsion force. + refinement_repulsion_threshold = 0.2 # Threshold distance for repulsion to start (e.g., 2*r_ideal for 0.1 circles) + refinement_boundary_margin = 0.1 # Distance from boundary where repulsion starts. + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # a. Calculate circle-circle repulsion forces. + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # b. Calculate boundary repulsion forces. + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + # c. Update center positions. + centers += refinement_step_size * forces + + # d. Clip centers. + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..21fef4b83a386ade3df458f01b1f7ace2f92cc8c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_57/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_57/results +Run 1/1 completed in 0.91 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9686221421685377 + public: {'centers_str': ' centers[0] = (0.0994, 0.0994)\n centers[1] = (0.2984, 0.0943)\n centers[2] = (0.5016, 0.0943)\n centers[3] = (0.7006, 0.0994)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0943, 0.2984)\n centers[6] = (0.2767, 0.2767)\n centers[7] = (0.5233, 0.2767)\n centers[8] = (0.7057, 0.2984)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0943, 0.5016)\n centers[11] = (0.2767, 0.5233)\n centers[12] = (0.5233, 0.5233)\n centers[13] = (0.7057, 0.5016)\n centers[14] = (0.9002, 0.5000)\n centers[15] = (0.0994, 0.7006)\n centers[16] = (0.2984, 0.7057)\n centers[17] = (0.5016, 0.7057)\n centers[18] = (0.7006, 0.7006)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1000, 0.9000)\n centers[21] = (0.3000, 0.9002)\n centers[22] = (0.5000, 0.9002)\n centers[23] = (0.7000, 0.9000)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9686221421685377} + visualization_path: + execution_time_mean: 0.9128705286420882 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..bd1698f9e5e7a4d5462e8579265d8dd621a7b85f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9686221421685377, + "public": { + "centers_str": " centers[0] = (0.0994, 0.0994)\n centers[1] = (0.2984, 0.0943)\n centers[2] = (0.5016, 0.0943)\n centers[3] = (0.7006, 0.0994)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0943, 0.2984)\n centers[6] = (0.2767, 0.2767)\n centers[7] = (0.5233, 0.2767)\n centers[8] = (0.7057, 0.2984)\n centers[9] = (0.9002, 0.3000)\n centers[10] = (0.0943, 0.5016)\n centers[11] = (0.2767, 0.5233)\n centers[12] = (0.5233, 0.5233)\n centers[13] = (0.7057, 0.5016)\n centers[14] = (0.9002, 0.5000)\n centers[15] = (0.0994, 0.7006)\n centers[16] = (0.2984, 0.7057)\n centers[17] = (0.5016, 0.7057)\n centers[18] = (0.7006, 0.7006)\n centers[19] = (0.9000, 0.7000)\n centers[20] = (0.1000, 0.9000)\n centers[21] = (0.3000, 0.9002)\n centers[22] = (0.5000, 0.9002)\n centers[23] = (0.7000, 0.9000)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9686221421685377 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_57/results/packing_viz.png", + "execution_time_mean": 0.9128705286420882, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..5b3253bd9642ab27ef6da19ad8d85d20fe6b343d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_57/search_replace.txt @@ -0,0 +1,166 @@ +Based on my analysis of the visual feedback and the code's structure, the current packing is stuck in a simple, suboptimal local minimum. The central region is highly inefficient, with one large circle suppressing its neighbors, creating wasted space. The single-stage relaxation process is not powerful enough to break out of this arrangement. + +My proposed edits reintroduce a more sophisticated, two-stage relaxation process (exploration and refinement) which is a proven technique for these kinds of problems. This is coupled with a stronger initial "push" to create more room for this dynamic rearrangement to occur. + + +increase_gaussian_amplitude + + + +The current visualization shows a central circle that is large, but the surrounding circles are too small, indicating they are squeezed. To give the central cluster of circles more room to rearrange into a more efficient, interlocking pattern, I am increasing the `amplitude` of the initial Gaussian push from 0.042 to 0.05. This will create a larger initial void, promoting a more dynamic exploration phase and helping the system escape the simple "big circle, small neighbors" local minimum. + + + +<<<<<<< SEARCH + # Hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. Increased slightly to make more room. + sigma = 0.15 # The "spread" of the push, controlling its influence range. +======= + # Hyperparameters for the Gaussian push: + amplitude = 0.05 # The maximum distance to push a circle. Increased to create a larger void. + sigma = 0.15 # The "spread" of the push, controlling its influence range. +>>>>>>> REPLACE + + + +reintroduce_two_stage_relaxation + + + +The current single-stage refinement process is too gentle to break the initial grid symmetry, resulting in an inefficient packing in the center as seen in the visualization. I am replacing it with a two-stage "exploration-refinement" strategy, which has proven effective in prior versions. + +1. **Exploration Stage:** Uses high-energy parameters (larger step size, stronger forces, 250 iterations) to aggressively shuffle the circles and explore a wider range of configurations, breaking out of the initial local minimum. +2. **Refinement Stage:** Uses low-energy parameters (smaller step size, weaker forces, 500 iterations) to carefully fine-tune the circle positions discovered during exploration, settling them into a dense local optimum. + +This method directly addresses the observed spatial inefficiency by first creating chaos and then carefully restoring order, allowing for the formation of more complex and efficient packing structures. I've also tuned the `boundary_margin` and `repulsion_threshold` for better space utilization. + + + +<<<<<<< SEARCH + # 5. Iteratively refine positions for all 26 circles after the initial deformation. + # This allows all circles, including the 26th, to find more optimal positions + # through mutual repulsion and boundary interactions. + refinement_iters = 80 # Number of refinement steps. Increased for more thorough relaxation. + refinement_step_size = 0.002 # Step size for center adjustments. + refinement_repulsion_strength = 0.02 # Multiplier for circle-circle repulsion force. + refinement_boundary_strength = 0.1 # Multiplier for wall-repulsion force. + refinement_repulsion_threshold = 0.2 # Threshold distance for repulsion to start (e.g., 2*r_ideal for 0.1 circles) + refinement_boundary_margin = 0.1 # Distance from boundary where repulsion starts. + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # a. Calculate circle-circle repulsion forces. + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # b. Calculate boundary repulsion forces. + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + # c. Update center positions. + centers += refinement_step_size * forces + + # d. Clip centers. + centers = np.clip(centers, 0.0, 1.0) +======= + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This approach uses a high-energy "exploration" phase to break symmetry + # and find a good general configuration, followed by a low-energy + # "refinement" phase to fine-tune the positions. + + # Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to quickly move circles + # out of the initial grid structure and explore new arrangements. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + repulsion_threshold = 0.19 # A common threshold for both stages + boundary_margin = 0.04 # Use a smaller margin to utilize edge space better + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) +>>>>>>> REPLACE + + + +idiomatic_radii_initialization + + + +In `compute_max_radii`, the `radii` array was initialized with `np.ones(n)` and then immediately overwritten in the subsequent loop. I am changing this to initialize with `np.zeros(n)`, which is more idiomatic and slightly clearer, as it doesn't suggest the initial values of 1 have any meaning. This is a minor code quality improvement with no change to the logic. + + + +<<<<<<< SEARCH + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): +======= + n = centers.shape[0] + radii = np.zeros(n) + + # First, limit by distance to square borders + for i in range(n): +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7a050dcbdf2f3b4f0dccd68e4fb5147cc4c4fb59 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..a37c330cd238007db7e468baa1409b3401ef5297 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/edit.diff @@ -0,0 +1,204 @@ +--- a/original.py ++++ b/original.py +@@ -1,126 +1,198 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a Gaussian repulsion to create a central void. + # This method, inspired by a successful prior program, pushes circles + # away from a central point to make space for the 26th circle. This + # allows for a more global and efficient rearrangement of the packing. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 # Tuned displacement magnitude + sigma = 0.15 # Range of the repulsive force + + grid_centers = centers[:25].copy() + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + centers[:25] = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the 26th circle in the center of the created void. + centers[25] = void_center + +- # Safeguard: clip centers to stay within the unit square. +- centers = np.clip(centers, 0.0001, 0.9999) ++ # Ensure centers remain within bounds after initial placement ++ centers = np.clip(centers, 0.0, 1.0) + +- # Compute maximum valid radii for this improved configuration ++ # 4. Two-Stage Adaptive Force-Directed Relaxation. ++ # This improves upon simple iterative refinement by using different ++ # force parameters for exploration (global adjustment) and refinement (fine-tuning). ++ ++ # Shared parameters for both stages: ++ repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) ++ boundary_margin = 0.04 # How close circles can get to boundary before repulsion ++ ++ # Stage 1: Exploration - Broad adjustment and global distribution ++ # Aims to rapidly resolve initial overlaps and broadly distribute circles. ++ exploration_iters = 100 ++ exploration_step_size = 0.0025 ++ exploration_repulsion_strength = 0.015 ++ exploration_boundary_strength = 0.075 ++ ++ for _ in range(exploration_iters): ++ forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers += exploration_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ # Stage 2: Refinement - Fine-tuning and precise adjustments ++ # Uses smaller movements to converge to a better local optimum. ++ refinement_iters = 150 ++ refinement_step_size = 0.0008 # Much smaller step size ++ refinement_repulsion_strength = 0.005 # Weaker repulsion ++ refinement_boundary_strength = 0.025 # Weaker boundary repulsion ++ ++ for _ in range(refinement_iters): ++ forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers += refinement_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ # 5. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/main.py new file mode 100644 index 0000000000000000000000000000000000000000..257b544a33a695ec1146a02c3e4e7b89ad1934ed --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/main.py @@ -0,0 +1,198 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a Gaussian repulsion to create a central void. + # This method, inspired by a successful prior program, pushes circles + # away from a central point to make space for the 26th circle. This + # allows for a more global and efficient rearrangement of the packing. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 # Tuned displacement magnitude + sigma = 0.15 # Range of the repulsive force + + grid_centers = centers[:25].copy() + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + centers[:25] = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Ensure centers remain within bounds after initial placement + centers = np.clip(centers, 0.0, 1.0) + + # 4. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) + boundary_margin = 0.04 # How close circles can get to boundary before repulsion + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/original.py new file mode 100644 index 0000000000000000000000000000000000000000..c6cb8006b0ac625a7315d0a2cf4159eb339533ea --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/original.py @@ -0,0 +1,126 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # This strategy builds upon the optimal packing for 25 circles (a 5x5 grid), + # which provides a very strong and dense foundation. + # The 26th circle is then placed in a central interstitial void. + + # 1. Place 25 circles in a 5x5 grid. + # This is the known optimal packing for 25 equal circles. + x_coords_5 = np.linspace(0.1, 0.9, 5) + y_coords_5 = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords_5, y_coords_5) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a Gaussian repulsion to create a central void. + # This method, inspired by a successful prior program, pushes circles + # away from a central point to make space for the 26th circle. This + # allows for a more global and efficient rearrangement of the packing. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 # Tuned displacement magnitude + sigma = 0.15 # Range of the repulsive force + + grid_centers = centers[:25].copy() + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + centers[:25] = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Safeguard: clip centers to stay within the unit square. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..31de15636a4e23482641b45ee0fdccd006500c6e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_59/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_59/results +Run 1/1 completed in 0.25 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9635652269686839 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9635652269686839} + visualization_path: + execution_time_mean: 0.2481595790013671 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..4fcefd21d8f54075f4919ce2184307adfbc80562 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9635652269686839, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9635652269686839 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_59/results/packing_viz.png", + "execution_time_mean": 0.2481595790013671, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..adcc78578850fc330eb48559f061013a6d6f925f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_59/search_replace.txt @@ -0,0 +1,99 @@ + +Reintroduce a two-stage force-directed relaxation. +The current visualization shows a static arrangement where circles around the central void are significantly smaller. This suggests suboptimal positioning due to the initial Gaussian deformation alone. Reintroducing force-directed relaxation, as seen in successful prior programs, allows circle centers to dynamically adjust, resolve overlaps, and find better positions to maximize their radii. This iterative movement should lead to a more balanced and dense packing than just a static placement followed by radius shrinking. The Gaussian deformation provides a good initial guess, and the relaxation refines it. + + +<<<<<<< SEARCH + # 3. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Safeguard: clip centers to stay within the unit square. + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this improved configuration + radii = compute_max_radii(centers) + return centers, radii +======= + # 3. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # Ensure centers remain within bounds after initial placement + centers = np.clip(centers, 0.0, 1.0) + + # 4. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) + boundary_margin = 0.04 # How close circles can get to boundary before repulsion + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f965a63e6254bf569bd67833f0a23ff92c72768a Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..a2cfef89816399d491b23f9a675d5122e7382f02 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/edit.diff @@ -0,0 +1,99 @@ +--- a/original.py ++++ b/original.py +@@ -1,94 +1,94 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Place circles in a structured pattern + # This is a simple pattern - evolution will improve this + + # First, place a large circle in the center + centers[0] = [0.5, 0.5] + + # Place 8 circles around it in a ring + for i in range(8): + angle = 2 * np.pi * i / 8 +- centers[i + 1] = [0.5 + 0.3 * np.cos(angle), 0.5 + 0.3 * np.sin(angle)] ++ centers[i + 1] = [0.5 + 0.22 * np.cos(angle), 0.5 + 0.22 * np.sin(angle)] + + # Place 16 more circles in an outer ring + for i in range(16): + angle = 2 * np.pi * i / 16 +- centers[i + 9] = [0.5 + 0.7 * np.cos(angle), 0.5 + 0.7 * np.sin(angle)] ++ centers[i + 9] = [0.5 + 0.41 * np.cos(angle), 0.5 + 0.41 * np.sin(angle)] + + # Additional positioning adjustment to make sure all circles + # are inside the square and don't overlap + # Clip to ensure everything is inside the unit square + centers = np.clip(centers, 0.01, 0.99) + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/main.py new file mode 100644 index 0000000000000000000000000000000000000000..b51170bfb8b3df3b29922351f29bcf11f69e7443 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/main.py @@ -0,0 +1,94 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Place circles in a structured pattern + # This is a simple pattern - evolution will improve this + + # First, place a large circle in the center + centers[0] = [0.5, 0.5] + + # Place 8 circles around it in a ring + for i in range(8): + angle = 2 * np.pi * i / 8 + centers[i + 1] = [0.5 + 0.22 * np.cos(angle), 0.5 + 0.22 * np.sin(angle)] + + # Place 16 more circles in an outer ring + for i in range(16): + angle = 2 * np.pi * i / 16 + centers[i + 9] = [0.5 + 0.41 * np.cos(angle), 0.5 + 0.41 * np.sin(angle)] + + # Additional positioning adjustment to make sure all circles + # are inside the square and don't overlap + # Clip to ensure everything is inside the unit square + centers = np.clip(centers, 0.01, 0.99) + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/original.py new file mode 100644 index 0000000000000000000000000000000000000000..f52133ed39da8e9d823b52b994ee5063132aad94 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/original.py @@ -0,0 +1,94 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Place circles in a structured pattern + # This is a simple pattern - evolution will improve this + + # First, place a large circle in the center + centers[0] = [0.5, 0.5] + + # Place 8 circles around it in a ring + for i in range(8): + angle = 2 * np.pi * i / 8 + centers[i + 1] = [0.5 + 0.3 * np.cos(angle), 0.5 + 0.3 * np.sin(angle)] + + # Place 16 more circles in an outer ring + for i in range(16): + angle = 2 * np.pi * i / 16 + centers[i + 9] = [0.5 + 0.7 * np.cos(angle), 0.5 + 0.7 * np.sin(angle)] + + # Additional positioning adjustment to make sure all circles + # are inside the square and don't overlap + # Clip to ensure everything is inside the unit square + centers = np.clip(centers, 0.01, 0.99) + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..dd0740d3568db8adefdeae5a30039035a02c0da0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_6/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_6/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.543652791354432 + public: {'centers_str': ' centers[0] = (0.5000, 0.5000)\n centers[1] = (0.7200, 0.5000)\n centers[2] = (0.6556, 0.6556)\n centers[3] = (0.5000, 0.7200)\n centers[4] = (0.3444, 0.6556)\n centers[5] = (0.2800, 0.5000)\n centers[6] = (0.3444, 0.3444)\n centers[7] = (0.5000, 0.2800)\n centers[8] = (0.6556, 0.3444)\n centers[9] = (0.9100, 0.5000)\n centers[10] = (0.8788, 0.6569)\n centers[11] = (0.7899, 0.7899)\n centers[12] = (0.6569, 0.8788)\n centers[13] = (0.5000, 0.9100)\n centers[14] = (0.3431, 0.8788)\n centers[15] = (0.2101, 0.7899)\n centers[16] = (0.1212, 0.6569)\n centers[17] = (0.0900, 0.5000)\n centers[18] = (0.1212, 0.3431)\n centers[19] = (0.2101, 0.2101)\n centers[20] = (0.3431, 0.1212)\n centers[21] = (0.5000, 0.0900)\n centers[22] = (0.6569, 0.1212)\n centers[23] = (0.7899, 0.2101)\n centers[24] = (0.8788, 0.3431)\n centers[25] = (0.0100, 0.0100)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.543652791354432} + visualization_path: + execution_time_mean: 0.003192984964698553 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..ee5bc5113a0e2ebe34dd0e4dd766bf669069f0fc --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.543652791354432, + "public": { + "centers_str": " centers[0] = (0.5000, 0.5000)\n centers[1] = (0.7200, 0.5000)\n centers[2] = (0.6556, 0.6556)\n centers[3] = (0.5000, 0.7200)\n centers[4] = (0.3444, 0.6556)\n centers[5] = (0.2800, 0.5000)\n centers[6] = (0.3444, 0.3444)\n centers[7] = (0.5000, 0.2800)\n centers[8] = (0.6556, 0.3444)\n centers[9] = (0.9100, 0.5000)\n centers[10] = (0.8788, 0.6569)\n centers[11] = (0.7899, 0.7899)\n centers[12] = (0.6569, 0.8788)\n centers[13] = (0.5000, 0.9100)\n centers[14] = (0.3431, 0.8788)\n centers[15] = (0.2101, 0.7899)\n centers[16] = (0.1212, 0.6569)\n centers[17] = (0.0900, 0.5000)\n centers[18] = (0.1212, 0.3431)\n centers[19] = (0.2101, 0.2101)\n centers[20] = (0.3431, 0.1212)\n centers[21] = (0.5000, 0.0900)\n centers[22] = (0.6569, 0.1212)\n centers[23] = (0.7899, 0.2101)\n centers[24] = (0.8788, 0.3431)\n centers[25] = (0.0100, 0.0100)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.543652791354432 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_6/results/packing_viz.png", + "execution_time_mean": 0.003192984964698553, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..02580ec38a852f5b9cbdf629cbd3094a2097fd53 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_6/search_replace.txt @@ -0,0 +1,39 @@ +Excellent. As a mathematician specializing in circle packing, I have analyzed the provided visualization and identified a critical flaw in the current approach. + +The visualization clearly shows a highly inefficient arrangement. The 16 circles in the "outer ring" are all squashed against the boundaries of the unit square, resulting in minuscule radii and contributing almost nothing to the total sum. This is a direct consequence of the initial placement algorithm attempting to place them with a ring radius of 0.7, which puts their centers outside the square, before they are clipped back to the edge. The large, unused empty space between the central cluster and this outer ring further highlights the inefficiency. + +My proposed edit directly addresses this fundamental problem. By significantly reducing the radii of both the inner and outer rings, I will create a more compact and spatially coherent initial arrangement. This ensures all circle centers are placed well within the unit square from the start, allowing the `compute_max_radii` function to work on a much more promising configuration and find substantially larger radii for all 26 circles. + + +compact_rings + + + +The current circle placement uses concentric rings with radii 0.3 and 0.7. The outer ring radius of 0.7 is too large, causing centers to be generated outside the unit square (e.g., at x=1.2). The subsequent clipping `np.clip(centers, 0.01, 0.99)` forces these 16 circles to the boundary, severely limiting their radii to ~0.01 and wasting a significant portion of the circle count. + +This edit reduces the ring radii to 0.22 and 0.41. This creates a more compact initial structure where all 26 circles are placed well inside the unit square. This gives the `compute_max_radii` function a much better starting configuration to work with, allowing it to find larger radii for all circles and better utilize the available space, which should dramatically increase the total sum of radii. + + + +<<<<<<< SEARCH + # Place 8 circles around it in a ring + for i in range(8): + angle = 2 * np.pi * i / 8 + centers[i + 1] = [0.5 + 0.3 * np.cos(angle), 0.5 + 0.3 * np.sin(angle)] + + # Place 16 more circles in an outer ring + for i in range(16): + angle = 2 * np.pi * i / 16 + centers[i + 9] = [0.5 + 0.7 * np.cos(angle), 0.5 + 0.7 * np.sin(angle)] +======= + # Place 8 circles around it in a ring + for i in range(8): + angle = 2 * np.pi * i / 8 + centers[i + 1] = [0.5 + 0.22 * np.cos(angle), 0.5 + 0.22 * np.sin(angle)] + + # Place 16 more circles in an outer ring + for i in range(16): + angle = 2 * np.pi * i / 16 + centers[i + 9] = [0.5 + 0.41 * np.cos(angle), 0.5 + 0.41 * np.sin(angle)] +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b94539f3e5ba81c3b57017d9b141a37db1baccab Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..72e50f286c1dfd157dffffb71db98463c62e6e69 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/edit.diff @@ -0,0 +1,269 @@ +--- a/original.py ++++ b/original.py +@@ -1,171 +1,169 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" ++"""Target-driven relaxation packing for n=26 circles""" + + import numpy as np + +- + def construct_packing(): + """ +- Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid +- and applying a two-stage (exploration/refinement) force-directed relaxation. ++ Constructs a high-density arrangement of 26 circles using a novel ++ target-driven relaxation method. This method dynamically adjusts forces ++ based on the current maximum potential radii of the circles. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + +- # 1. Start with the 25 centers of a 5x5 grid. ++ # 1. Initial Placement: 5x5 grid + one circle in a central void. ++ # This provides a structured, high-density starting point. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T +- +- # 2. Define the center of the void where the 26th circle will be placed. ++ centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T ++ centers[25] = [0.4, 0.4] ++ ++ # Use an initial Gaussian deformation to break symmetry and create space, ++ # providing a better starting configuration for the relaxation algorithm. + void_center = np.array([0.4, 0.4]) +- +- # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. +- deformed_centers_25 = np.copy(base_centers_25) +- +- # Increased amplitude to create a larger initial void. ++ base_centers_25 = np.copy(centers[:25]) + amplitude = 0.05 + sigma = 0.15 +- + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) +- displacement = direction * push_magnitude +- deformed_centers_25[i] += displacement +- +- centers[:25] = deformed_centers_25 +- centers[25] = void_center ++ centers[i] += direction * push_magnitude + centers = np.clip(centers, 0.0, 1.0) + +- # 4. Stage 1: High-Energy Exploration +- # This stage uses strong forces and a large step size to break the initial +- # grid structure and find a better global arrangement. +- exploration_iters = 250 +- exploration_step_size = 0.003 +- exploration_repulsion_strength = 0.02 +- exploration_boundary_strength = 0.1 +- repulsion_threshold = 0.20 # Increased threshold to encourage movement +- boundary_margin = 0.04 # Smaller margin to better utilize edges ++ # 2. Two-Stage Target-Driven Relaxation ++ # The core of the new algorithm. It uses a physically-inspired force model ++ # where the ideal separation is derived from the circles' current potential radii. + +- for _ in range(exploration_iters): ++ # Stage 1: Settling Phase - High energy to find a good configuration quickly ++ settling_params = { ++ 'iters': 200, ++ 'step_size': 0.1, ++ 'interaction_strength': 0.1, ++ 'boundary_strength': 1.5, ++ } ++ centers = run_dynamic_relaxation(centers, settling_params) ++ ++ # Stage 2: Refinement Phase - Low energy for fine-tuning and convergence ++ refinement_params = { ++ 'iters': 300, ++ 'step_size': 0.02, ++ 'interaction_strength': 0.05, ++ 'boundary_strength': 2.0, ++ } ++ centers = run_dynamic_relaxation(centers, refinement_params) ++ ++ # 3. Final, high-precision radii computation for the optimized centers. ++ radii = compute_max_radii(centers, final_pass=True) ++ return centers, radii ++ ++def run_dynamic_relaxation(centers, params): ++ """ ++ Performs target-driven relaxation on a set of circle centers. ++ ++ Args: ++ centers: The initial positions of the circle centers. ++ params: A dictionary of parameters for the relaxation stage. ++ ++ Returns: ++ The final positions of the circle centers. ++ """ ++ n = centers.shape[0] ++ ++ for _ in range(params['iters']): ++ # Crucial step: Calculate the optimal radii for the current positions. ++ # These radii become the 'target' for our force calculations. ++ target_radii = compute_max_radii(centers, final_pass=False) ++ + forces = np.zeros_like(centers) ++ ++ # Circle-circle interaction forces (spring-like) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist ++ ++ # The ideal separation is the sum of the target radii. ++ ideal_dist = target_radii[i] + target_radii[j] ++ ++ if dist > 1e-9: ++ delta = ideal_dist - dist ++ force_mag = params['interaction_strength'] * delta + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec ++ ++ # Adaptive boundary interaction forces + for i in range(n): + x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) +- centers += exploration_step_size * forces ++ radius = target_radii[i] ++ ++ if x < radius: forces[i, 0] += params['boundary_strength'] * (radius - x) ++ if x > 1 - radius: forces[i, 0] -= params['boundary_strength'] * (x - (1 - radius)) ++ if y < radius: forces[i, 1] += params['boundary_strength'] * (radius - y) ++ if y > 1 - radius: forces[i, 1] -= params['boundary_strength'] * (y - (1 - radius)) ++ ++ # Update centers and clip to stay within the unit square ++ centers += params['step_size'] * forces + centers = np.clip(centers, 0.0, 1.0) ++ ++ return centers + +- # 5. Stage 2: Low-Energy Refinement +- # This stage uses more iterations with weaker forces and a smaller step size +- # to fine-tune the circle positions and settle into a dense local optimum. +- refinement_iters = 400 +- refinement_step_size = 0.0005 +- refinement_repulsion_strength = 0.008 +- refinement_boundary_strength = 0.04 +- +- for _ in range(refinement_iters): +- forces = np.zeros_like(centers) +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_mag = refinement_repulsion_strength * (repulsion_threshold - dist) / dist +- force_vec = force_mag * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- for i in range(n): +- x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) +- centers += refinement_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- +- # 6. Compute maximum valid radii for the refined configuration. +- radii = compute_max_radii(centers) +- return centers, radii +- +- +-def compute_max_radii(centers): ++def compute_max_radii(centers, final_pass=False): + """ +- Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This is +- an iterative version that converges to a stable solution. ++ Compute the maximum possible radii for each circle position. ++ Uses fewer iterations for speed during relaxation steps and more for the final pass. + + Args: +- centers: np.array of shape (n, 2) with (x, y) coordinates ++ centers: np.array of shape (n, 2) with (x, y) coordinates. ++ final_pass: Boolean, if True, uses more iterations for higher accuracy. + + Returns: +- np.array of shape (n) with radius of each circle ++ np.array of shape (n) with the radius of each circle. + """ + n = centers.shape[0] +- +- # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + +- # Iteratively resolve overlaps between circles until no more changes occur. +- # A high number of iterations ensures convergence for complex arrangements. +- for _ in range(500): ++ # Use fewer iterations during the simulation for speed, more for the final result. ++ iterations = 400 if final_pass else 80 ++ ++ for _ in range(iterations): + changed_in_pass = False +- # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) +- +- # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: +- # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] +- if sum_r > 1e-12: # Avoid division by zero ++ if sum_r > 1e-12: + scale = dist / sum_r +- radii[i] *= scale +- radii[j] *= scale +- else: # If both radii are already ~0, ensure they are exactly 0 +- radii[i] = 0 +- radii[j] = 0 +- +- changed_in_pass = True +- +- # If a full pass resulted in no changes, the packing is stable. ++ new_ri = radii[i] * scale ++ new_rj = radii[j] * scale ++ if new_ri < radii[i] or new_rj < radii[j]: ++ radii[i] = new_ri ++ radii[j] = new_rj ++ changed_in_pass = True + if not changed_in_pass: + break +- + return radii +- +- + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/main.py new file mode 100644 index 0000000000000000000000000000000000000000..5a1197bc45a9fb842f8d446c4a027f76983ed31e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/main.py @@ -0,0 +1,169 @@ +# EVOLVE-BLOCK-START +"""Target-driven relaxation packing for n=26 circles""" + +import numpy as np + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a novel + target-driven relaxation method. This method dynamically adjusts forces + based on the current maximum potential radii of the circles. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Placement: 5x5 grid + one circle in a central void. + # This provides a structured, high-density starting point. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + centers[25] = [0.4, 0.4] + + # Use an initial Gaussian deformation to break symmetry and create space, + # providing a better starting configuration for the relaxation algorithm. + void_center = np.array([0.4, 0.4]) + base_centers_25 = np.copy(centers[:25]) + amplitude = 0.05 + sigma = 0.15 + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + centers[i] += direction * push_magnitude + centers = np.clip(centers, 0.0, 1.0) + + # 2. Two-Stage Target-Driven Relaxation + # The core of the new algorithm. It uses a physically-inspired force model + # where the ideal separation is derived from the circles' current potential radii. + + # Stage 1: Settling Phase - High energy to find a good configuration quickly + settling_params = { + 'iters': 200, + 'step_size': 0.1, + 'interaction_strength': 0.1, + 'boundary_strength': 1.5, + } + centers = run_dynamic_relaxation(centers, settling_params) + + # Stage 2: Refinement Phase - Low energy for fine-tuning and convergence + refinement_params = { + 'iters': 300, + 'step_size': 0.02, + 'interaction_strength': 0.05, + 'boundary_strength': 2.0, + } + centers = run_dynamic_relaxation(centers, refinement_params) + + # 3. Final, high-precision radii computation for the optimized centers. + radii = compute_max_radii(centers, final_pass=True) + return centers, radii + +def run_dynamic_relaxation(centers, params): + """ + Performs target-driven relaxation on a set of circle centers. + + Args: + centers: The initial positions of the circle centers. + params: A dictionary of parameters for the relaxation stage. + + Returns: + The final positions of the circle centers. + """ + n = centers.shape[0] + + for _ in range(params['iters']): + # Crucial step: Calculate the optimal radii for the current positions. + # These radii become the 'target' for our force calculations. + target_radii = compute_max_radii(centers, final_pass=False) + + forces = np.zeros_like(centers) + + # Circle-circle interaction forces (spring-like) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + + # The ideal separation is the sum of the target radii. + ideal_dist = target_radii[i] + target_radii[j] + + if dist > 1e-9: + delta = ideal_dist - dist + force_mag = params['interaction_strength'] * delta + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Adaptive boundary interaction forces + for i in range(n): + x, y = centers[i] + radius = target_radii[i] + + if x < radius: forces[i, 0] += params['boundary_strength'] * (radius - x) + if x > 1 - radius: forces[i, 0] -= params['boundary_strength'] * (x - (1 - radius)) + if y < radius: forces[i, 1] += params['boundary_strength'] * (radius - y) + if y > 1 - radius: forces[i, 1] -= params['boundary_strength'] * (y - (1 - radius)) + + # Update centers and clip to stay within the unit square + centers += params['step_size'] * forces + centers = np.clip(centers, 0.0, 1.0) + + return centers + +def compute_max_radii(centers, final_pass=False): + """ + Compute the maximum possible radii for each circle position. + Uses fewer iterations for speed during relaxation steps and more for the final pass. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates. + final_pass: Boolean, if True, uses more iterations for higher accuracy. + + Returns: + np.array of shape (n) with the radius of each circle. + """ + n = centers.shape[0] + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Use fewer iterations during the simulation for speed, more for the final result. + iterations = 400 if final_pass else 80 + + for _ in range(iterations): + changed_in_pass = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + new_ri = radii[i] * scale + new_rj = radii[j] * scale + if new_ri < radii[i] or new_rj < radii[j]: + radii[i] = new_ri + radii[j] = new_rj + changed_in_pass = True + if not changed_in_pass: + break + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/original.py new file mode 100644 index 0000000000000000000000000000000000000000..cd2a1c594f5f62160d5dedc59030456cbcbc0e88 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/original.py @@ -0,0 +1,171 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + and applying a two-stage (exploration/refinement) force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.05 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to break the initial + # grid structure and find a better global arrangement. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + repulsion_threshold = 0.20 # Increased threshold to encourage movement + boundary_margin = 0.04 # Smaller margin to better utilize edges + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to fine-tune the circle positions and settle into a dense local optimum. + refinement_iters = 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..d74c7ab07347346b8b8cea4f0f9b9af3cdd33813 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_60/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_60/results +Run 1/1 completed in 1.87 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 8.398726105915437e-06 + public: {'centers_str': ' centers[0] = (0.4962, 0.4962)\n centers[1] = (0.4962, 0.4962)\n centers[2] = (0.4962, 0.4962)\n centers[3] = (0.4962, 0.4962)\n centers[4] = (0.4962, 0.4962)\n centers[5] = (0.4962, 0.4962)\n centers[6] = (0.4962, 0.4962)\n centers[7] = (0.4962, 0.4962)\n centers[8] = (0.4962, 0.4962)\n centers[9] = (0.4962, 0.4962)\n centers[10] = (0.4962, 0.4962)\n centers[11] = (0.4962, 0.4962)\n centers[12] = (0.4962, 0.4962)\n centers[13] = (0.4962, 0.4962)\n centers[14] = (0.4962, 0.4962)\n centers[15] = (0.4962, 0.4962)\n centers[16] = (0.4962, 0.4962)\n centers[17] = (0.4962, 0.4962)\n centers[18] = (0.4962, 0.4962)\n centers[19] = (0.4962, 0.4962)\n centers[20] = (0.4962, 0.4962)\n centers[21] = (0.4962, 0.4962)\n centers[22] = (0.4962, 0.4962)\n centers[23] = (0.4962, 0.4962)\n centers[24] = (0.4962, 0.4962)\n centers[25] = (0.4962, 0.4962)', 'num_circles': 26} + private: {'reported_sum_of_radii': 8.398726105915437e-06} + visualization_path: + execution_time_mean: 1.8687811424024403 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..8b578f07370cea029fc5b3276dac037f2494dc3d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 8.398726105915437e-06, + "public": { + "centers_str": " centers[0] = (0.4962, 0.4962)\n centers[1] = (0.4962, 0.4962)\n centers[2] = (0.4962, 0.4962)\n centers[3] = (0.4962, 0.4962)\n centers[4] = (0.4962, 0.4962)\n centers[5] = (0.4962, 0.4962)\n centers[6] = (0.4962, 0.4962)\n centers[7] = (0.4962, 0.4962)\n centers[8] = (0.4962, 0.4962)\n centers[9] = (0.4962, 0.4962)\n centers[10] = (0.4962, 0.4962)\n centers[11] = (0.4962, 0.4962)\n centers[12] = (0.4962, 0.4962)\n centers[13] = (0.4962, 0.4962)\n centers[14] = (0.4962, 0.4962)\n centers[15] = (0.4962, 0.4962)\n centers[16] = (0.4962, 0.4962)\n centers[17] = (0.4962, 0.4962)\n centers[18] = (0.4962, 0.4962)\n centers[19] = (0.4962, 0.4962)\n centers[20] = (0.4962, 0.4962)\n centers[21] = (0.4962, 0.4962)\n centers[22] = (0.4962, 0.4962)\n centers[23] = (0.4962, 0.4962)\n centers[24] = (0.4962, 0.4962)\n centers[25] = (0.4962, 0.4962)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 8.398726105915437e-06 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/packing_viz.png", + "execution_time_mean": 1.8687811424024403, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/packing_viz.png b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/packing_viz.png new file mode 100644 index 0000000000000000000000000000000000000000..1e613090e265c7d192942d9536f819446db1a84a Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/results/packing_viz.png differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..7116ec916f7ef998fed228f8266a303b50016fbe --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_60/rewrite.txt @@ -0,0 +1,160 @@ +# EVOLVE-BLOCK-START +"""Target-driven relaxation packing for n=26 circles""" + +import numpy as np + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using a novel + target-driven relaxation method. This method dynamically adjusts forces + based on the current maximum potential radii of the circles. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Placement: 5x5 grid + one circle in a central void. + # This provides a structured, high-density starting point. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + centers[:25] = np.vstack([xx.ravel(), yy.ravel()]).T + centers[25] = [0.4, 0.4] + + # Use an initial Gaussian deformation to break symmetry and create space, + # providing a better starting configuration for the relaxation algorithm. + void_center = np.array([0.4, 0.4]) + base_centers_25 = np.copy(centers[:25]) + amplitude = 0.05 + sigma = 0.15 + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + centers[i] += direction * push_magnitude + centers = np.clip(centers, 0.0, 1.0) + + # 2. Two-Stage Target-Driven Relaxation + # The core of the new algorithm. It uses a physically-inspired force model + # where the ideal separation is derived from the circles' current potential radii. + + # Stage 1: Settling Phase - High energy to find a good configuration quickly + settling_params = { + 'iters': 200, + 'step_size': 0.1, + 'interaction_strength': 0.1, + 'boundary_strength': 1.5, + } + centers = run_dynamic_relaxation(centers, settling_params) + + # Stage 2: Refinement Phase - Low energy for fine-tuning and convergence + refinement_params = { + 'iters': 300, + 'step_size': 0.02, + 'interaction_strength': 0.05, + 'boundary_strength': 2.0, + } + centers = run_dynamic_relaxation(centers, refinement_params) + + # 3. Final, high-precision radii computation for the optimized centers. + radii = compute_max_radii(centers, final_pass=True) + return centers, radii + +def run_dynamic_relaxation(centers, params): + """ + Performs target-driven relaxation on a set of circle centers. + + Args: + centers: The initial positions of the circle centers. + params: A dictionary of parameters for the relaxation stage. + + Returns: + The final positions of the circle centers. + """ + n = centers.shape[0] + + for _ in range(params['iters']): + # Crucial step: Calculate the optimal radii for the current positions. + # These radii become the 'target' for our force calculations. + target_radii = compute_max_radii(centers, final_pass=False) + + forces = np.zeros_like(centers) + + # Circle-circle interaction forces (spring-like) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + + # The ideal separation is the sum of the target radii. + ideal_dist = target_radii[i] + target_radii[j] + + if dist > 1e-9: + delta = ideal_dist - dist + force_mag = params['interaction_strength'] * delta + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Adaptive boundary interaction forces + for i in range(n): + x, y = centers[i] + radius = target_radii[i] + + if x < radius: forces[i, 0] += params['boundary_strength'] * (radius - x) + if x > 1 - radius: forces[i, 0] -= params['boundary_strength'] * (x - (1 - radius)) + if y < radius: forces[i, 1] += params['boundary_strength'] * (radius - y) + if y > 1 - radius: forces[i, 1] -= params['boundary_strength'] * (y - (1 - radius)) + + # Update centers and clip to stay within the unit square + centers += params['step_size'] * forces + centers = np.clip(centers, 0.0, 1.0) + + return centers + +def compute_max_radii(centers, final_pass=False): + """ + Compute the maximum possible radii for each circle position. + Uses fewer iterations for speed during relaxation steps and more for the final pass. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates. + final_pass: Boolean, if True, uses more iterations for higher accuracy. + + Returns: + np.array of shape (n) with the radius of each circle. + """ + n = centers.shape[0] + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Use fewer iterations during the simulation for speed, more for the final result. + iterations = 400 if final_pass else 80 + + for _ in range(iterations): + changed_in_pass = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + new_ri = radii[i] * scale + new_rj = radii[j] * scale + if new_ri < radii[i] or new_rj < radii[j]: + radii[i] = new_ri + radii[j] = new_rj + changed_in_pass = True + if not changed_in_pass: + break + return radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be3f40a6d516e78df829de2ae2b26d7cdf89c93e Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..ef63d8d7458ecc42f1082d7996b34c3a73a86f7e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/edit.diff @@ -0,0 +1,224 @@ +--- a/original.py ++++ b/original.py +@@ -1,156 +1,194 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid (optimal for 25 circles), + deforms it by creating a void using a Gaussian repulsive force, + and then places the 26th circle into that new, larger void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an interstitial void center. + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the grid by "pushing" points away from the void center + # using a Gaussian repulsive model. This creates space for the 26th circle. + amplitude = 0.04 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # Ensure centers remain within the unit square after deformation. + deformed_centers = np.clip(deformed_centers, 0.0, 1.0) + + centers[:25] = deformed_centers + + # 4. Place the 26th circle in the center of the created void. + centers[25] = void_center + +- # 5. Relax the circle positions using a force-directed layout. +- # This allows circles to move and settle into a more efficient packing, +- # resolving the inefficient gaps created by the initial static deformation. +- num_iterations = 80 +- learning_rate = 3e-5 +- repulsion_strength = 1e-4 +- boundary_strength = 2e-3 ++ # 5. Two-Stage Adaptive Force-Directed Relaxation. ++ # This improves upon simple iterative refinement by using different ++ # force parameters for exploration (global adjustment) and refinement (fine-tuning). + +- for _ in range(num_iterations): +- # Inter-circle repulsion forces (vectorized) +- # Calculate vector differences and squared distances between all pairs +- diffs = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] +- dist_sq = np.sum(diffs**2, axis=-1) ++ # Shared parameters for both stages: ++ repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) ++ boundary_margin = 0.04 # How close circles can get to boundary before repulsion + +- # Avoid self-repulsion (force is zero) by setting diagonal to a large number +- np.fill_diagonal(dist_sq, 1e12) +- # Prevent division by zero if circles overlap +- dist_sq[dist_sq < 1e-9] = 1e-9 ++ # Stage 1: Exploration - Broad adjustment and global distribution ++ # Aims to rapidly resolve initial overlaps and broadly distribute circles. ++ exploration_iters = 100 ++ exploration_step_size = 0.0025 ++ exploration_repulsion_strength = 0.015 ++ exploration_boundary_strength = 0.075 + +- # Repulsion force is proportional to 1/distance (F ~ v/|v|^2) +- forces = repulsion_strength * np.sum(diffs / dist_sq[..., np.newaxis], axis=1) ++ for _ in range(exploration_iters): ++ forces = np.zeros_like(centers) + +- # Boundary repulsion forces (using a 1/d^2 model for strong repulsion near walls) +- forces[:, 0] += boundary_strength / (centers[:, 0]**2 + 1e-6) +- forces[:, 0] -= boundary_strength / ((1.0 - centers[:, 0])**2 + 1e-6) +- forces[:, 1] += boundary_strength / (centers[:, 1]**2 + 1e-6) +- forces[:, 1] -= boundary_strength / ((1.0 - centers[:, 1])**2 + 1e-6) ++ # Circle-circle repulsion ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec + +- # Update circle positions based on forces +- centers += learning_rate * forces ++ # Boundary repulsion ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + +- # Clip centers to ensure they stay within the square +- centers = np.clip(centers, 0.0001, 0.9999) ++ centers += exploration_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ # Stage 2: Refinement - Fine-tuning and precise adjustments ++ # Uses smaller movements to converge to a better local optimum. ++ refinement_iters = 150 ++ refinement_step_size = 0.0008 # Much smaller step size ++ refinement_repulsion_strength = 0.005 # Weaker repulsion ++ refinement_boundary_strength = 0.025 # Weaker boundary repulsion ++ ++ for _ in range(refinement_iters): ++ forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers += refinement_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) + + # Compute maximum valid radii for this newly relaxed configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/main.py new file mode 100644 index 0000000000000000000000000000000000000000..85fdb47c1d37aa6ddc0dfd79794fa46a5f9b6a7b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/main.py @@ -0,0 +1,194 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid (optimal for 25 circles), + deforms it by creating a void using a Gaussian repulsive force, + and then places the 26th circle into that new, larger void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an interstitial void center. + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the grid by "pushing" points away from the void center + # using a Gaussian repulsive model. This creates space for the 26th circle. + amplitude = 0.04 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # Ensure centers remain within the unit square after deformation. + deformed_centers = np.clip(deformed_centers, 0.0, 1.0) + + centers[:25] = deformed_centers + + # 4. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) + boundary_margin = 0.04 # How close circles can get to boundary before repulsion + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Compute maximum valid radii for this newly relaxed configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/original.py new file mode 100644 index 0000000000000000000000000000000000000000..a10c1f450c3a5e95f8db132204f3bb6338687093 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/original.py @@ -0,0 +1,156 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid (optimal for 25 circles), + deforms it by creating a void using a Gaussian repulsive force, + and then places the 26th circle into that new, larger void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an interstitial void center. + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the grid by "pushing" points away from the void center + # using a Gaussian repulsive model. This creates space for the 26th circle. + amplitude = 0.04 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # Ensure centers remain within the unit square after deformation. + deformed_centers = np.clip(deformed_centers, 0.0, 1.0) + + centers[:25] = deformed_centers + + # 4. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # 5. Relax the circle positions using a force-directed layout. + # This allows circles to move and settle into a more efficient packing, + # resolving the inefficient gaps created by the initial static deformation. + num_iterations = 80 + learning_rate = 3e-5 + repulsion_strength = 1e-4 + boundary_strength = 2e-3 + + for _ in range(num_iterations): + # Inter-circle repulsion forces (vectorized) + # Calculate vector differences and squared distances between all pairs + diffs = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] + dist_sq = np.sum(diffs**2, axis=-1) + + # Avoid self-repulsion (force is zero) by setting diagonal to a large number + np.fill_diagonal(dist_sq, 1e12) + # Prevent division by zero if circles overlap + dist_sq[dist_sq < 1e-9] = 1e-9 + + # Repulsion force is proportional to 1/distance (F ~ v/|v|^2) + forces = repulsion_strength * np.sum(diffs / dist_sq[..., np.newaxis], axis=1) + + # Boundary repulsion forces (using a 1/d^2 model for strong repulsion near walls) + forces[:, 0] += boundary_strength / (centers[:, 0]**2 + 1e-6) + forces[:, 0] -= boundary_strength / ((1.0 - centers[:, 0])**2 + 1e-6) + forces[:, 1] += boundary_strength / (centers[:, 1]**2 + 1e-6) + forces[:, 1] -= boundary_strength / ((1.0 - centers[:, 1])**2 + 1e-6) + + # Update circle positions based on forces + centers += learning_rate * forces + + # Clip centers to ensure they stay within the square + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this newly relaxed configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..d54e5a85a4a91382dcac401867e771a50e41da1f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_61/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_61/results +Run 1/1 completed in 0.36 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9623455299809731 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0959)\n centers[2] = (0.5014, 0.0959)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0959, 0.2986)\n centers[6] = (0.2815, 0.2815)\n centers[7] = (0.5185, 0.2815)\n centers[8] = (0.7041, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0959, 0.5014)\n centers[11] = (0.2815, 0.5185)\n centers[12] = (0.5185, 0.5185)\n centers[13] = (0.7041, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7041)\n centers[17] = (0.5014, 0.7041)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9623455299809731} + visualization_path: + execution_time_mean: 0.3570576529018581 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..72b5dd29fb5a5d0afae56b1d9a258700364078ac --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9623455299809731, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0959)\n centers[2] = (0.5014, 0.0959)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0959, 0.2986)\n centers[6] = (0.2815, 0.2815)\n centers[7] = (0.5185, 0.2815)\n centers[8] = (0.7041, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0959, 0.5014)\n centers[11] = (0.2815, 0.5185)\n centers[12] = (0.5185, 0.5185)\n centers[13] = (0.7041, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7041)\n centers[17] = (0.5014, 0.7041)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9623455299809731 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_61/results/packing_viz.png", + "execution_time_mean": 0.3570576529018581, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3152ec3e965012928924e5eb127726ab5ac5270 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_61/search_replace.txt @@ -0,0 +1,129 @@ + +replace_relaxation_with_two_stage + + + +Based on the visual feedback, the current arrangement shows a significant imbalance. The central circle is very large, which has caused its immediate neighbors to become disproportionately small, likely lowering the total sum of radii. This suggests the current relaxation method, which uses a single-stage, `1/d^2` force model, is too aggressive and locks the configuration into a suboptimal state. + +To address this, I am replacing the existing relaxation algorithm with a more sophisticated two-stage method that was successful in a previous program. This method consists of: +1. **Exploration Stage**: Uses larger forces and step sizes to make broad adjustments to the circle positions, moving them into a better general configuration. +2. **Refinement Stage**: Uses much smaller forces and step sizes to fine-tune the positions, settling them into a dense local optimum. + +This approach, with its gentler, threshold-based linear forces, should allow for a more balanced distribution of radii by preventing the "bullying" effect seen in the visualization and enabling a more cooperative settlement of the circles. + + + +<<<<<<< SEARCH + # 5. Relax the circle positions using a force-directed layout. + # This allows circles to move and settle into a more efficient packing, + # resolving the inefficient gaps created by the initial static deformation. + num_iterations = 80 + learning_rate = 3e-5 + repulsion_strength = 1e-4 + boundary_strength = 2e-3 + + for _ in range(num_iterations): + # Inter-circle repulsion forces (vectorized) + # Calculate vector differences and squared distances between all pairs + diffs = centers[:, np.newaxis, :] - centers[np.newaxis, :, :] + dist_sq = np.sum(diffs**2, axis=-1) + + # Avoid self-repulsion (force is zero) by setting diagonal to a large number + np.fill_diagonal(dist_sq, 1e12) + # Prevent division by zero if circles overlap + dist_sq[dist_sq < 1e-9] = 1e-9 + + # Repulsion force is proportional to 1/distance (F ~ v/|v|^2) + forces = repulsion_strength * np.sum(diffs / dist_sq[..., np.newaxis], axis=1) + + # Boundary repulsion forces (using a 1/d^2 model for strong repulsion near walls) + forces[:, 0] += boundary_strength / (centers[:, 0]**2 + 1e-6) + forces[:, 0] -= boundary_strength / ((1.0 - centers[:, 0])**2 + 1e-6) + forces[:, 1] += boundary_strength / (centers[:, 1]**2 + 1e-6) + forces[:, 1] -= boundary_strength / ((1.0 - centers[:, 1])**2 + 1e-6) + + # Update circle positions based on forces + centers += learning_rate * forces + + # Clip centers to ensure they stay within the square + centers = np.clip(centers, 0.0001, 0.9999) + + # Compute maximum valid radii for this newly relaxed configuration + radii = compute_max_radii(centers) +======= + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) + boundary_margin = 0.04 # How close circles can get to boundary before repulsion + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Compute maximum valid radii for this newly relaxed configuration + radii = compute_max_radii(centers) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e2475989392f13b21ff0467910b8e3a46eab0e8b Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..b336b27343f3e4e6127d2de3f09417f1bba16a82 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_62/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_62/results +Run 1/1 completed in 0.25 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9614290794469516 + public: {'centers_str': ' centers[0] = (0.0983, 0.0983)\n centers[1] = (0.2974, 0.0923)\n centers[2] = (0.5026, 0.0923)\n centers[3] = (0.7017, 0.0983)\n centers[4] = (0.9002, 0.0999)\n centers[5] = (0.0923, 0.2974)\n centers[6] = (0.2801, 0.2801)\n centers[7] = (0.5199, 0.2801)\n centers[8] = (0.7077, 0.2974)\n centers[9] = (0.9007, 0.2999)\n centers[10] = (0.0923, 0.5026)\n centers[11] = (0.2801, 0.5199)\n centers[12] = (0.5199, 0.5199)\n centers[13] = (0.7077, 0.5026)\n centers[14] = (0.9007, 0.5001)\n centers[15] = (0.0983, 0.7017)\n centers[16] = (0.2974, 0.7077)\n centers[17] = (0.5026, 0.7077)\n centers[18] = (0.7017, 0.7017)\n centers[19] = (0.9002, 0.7001)\n centers[20] = (0.0999, 0.9002)\n centers[21] = (0.2999, 0.9007)\n centers[22] = (0.5001, 0.9007)\n centers[23] = (0.7001, 0.9002)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9614290794469516} + visualization_path: + execution_time_mean: 0.24606186896562576 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..4c7ec772ed70bb1bd47879b401cc332acb1e9b3c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9614290794469516, + "public": { + "centers_str": " centers[0] = (0.0983, 0.0983)\n centers[1] = (0.2974, 0.0923)\n centers[2] = (0.5026, 0.0923)\n centers[3] = (0.7017, 0.0983)\n centers[4] = (0.9002, 0.0999)\n centers[5] = (0.0923, 0.2974)\n centers[6] = (0.2801, 0.2801)\n centers[7] = (0.5199, 0.2801)\n centers[8] = (0.7077, 0.2974)\n centers[9] = (0.9007, 0.2999)\n centers[10] = (0.0923, 0.5026)\n centers[11] = (0.2801, 0.5199)\n centers[12] = (0.5199, 0.5199)\n centers[13] = (0.7077, 0.5026)\n centers[14] = (0.9007, 0.5001)\n centers[15] = (0.0983, 0.7017)\n centers[16] = (0.2974, 0.7077)\n centers[17] = (0.5026, 0.7077)\n centers[18] = (0.7017, 0.7017)\n centers[19] = (0.9002, 0.7001)\n centers[20] = (0.0999, 0.9002)\n centers[21] = (0.2999, 0.9007)\n centers[22] = (0.5001, 0.9007)\n centers[23] = (0.7001, 0.9002)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9614290794469516 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_62/results/packing_viz.png", + "execution_time_mean": 0.24606186896562576, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ef243335e7b388b663eda358aa5027926a95d9b Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..63a52bc57ded4362fb2db7961e3747afd79530a9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/edit.diff @@ -0,0 +1,213 @@ +--- a/original.py ++++ b/original.py +@@ -1,193 +1,194 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. +- # A central interstitial void at (0.4, 0.4) is a good candidate. +- void_center = np.array([0.4, 0.4]) ++ # A central interstitial void at (0.5, 0.5) is a good candidate for symmetry. ++ void_center = np.array([0.5, 0.5]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + +- # Shared parameters for both stages: +- repulsion_threshold = 0.185 ++ # Shared parameters: + boundary_margin = 0.04 + n = centers.shape[0] + + # Stage 1: Exploration - Broad adjustment and global distribution +- exploration_iters = 100 +- exploration_step_size = 0.0025 +- exploration_repulsion_strength = 0.015 +- exploration_boundary_strength = 0.075 ++ exploration_iters = 250 # Increased iterations for better exploration ++ exploration_step_size = 0.003 # Slightly increased step size ++ exploration_repulsion_strength = 0.02 # Increased repulsion strength ++ exploration_boundary_strength = 0.1 # Increased boundary strength ++ exploration_repulsion_threshold = 0.20 # Distinct threshold for exploration + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist ++ if 0 < dist < exploration_repulsion_threshold: ++ force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments +- refinement_iters = 150 +- refinement_step_size = 0.0008 +- refinement_repulsion_strength = 0.005 +- refinement_boundary_strength = 0.025 ++ refinement_iters = 500 # Increased iterations for thorough fine-tuning ++ refinement_step_size = 0.0005 # Maintained for fine-tuning ++ refinement_repulsion_strength = 0.008 # Slightly increased repulsion strength ++ refinement_boundary_strength = 0.04 # Increased boundary strength ++ refinement_repulsion_threshold = 0.185 # Distinct threshold for refinement + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist ++ if 0 < dist < refinement_repulsion_threshold: ++ force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/main.py new file mode 100644 index 0000000000000000000000000000000000000000..08365c70897443c0276de50826bb2bb963ec140d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/main.py @@ -0,0 +1,194 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.5, 0.5) is a good candidate for symmetry. + void_center = np.array([0.5, 0.5]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters: + boundary_margin = 0.04 + n = centers.shape[0] + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 250 # Increased iterations for better exploration + exploration_step_size = 0.003 # Slightly increased step size + exploration_repulsion_strength = 0.02 # Increased repulsion strength + exploration_boundary_strength = 0.1 # Increased boundary strength + exploration_repulsion_threshold = 0.20 # Distinct threshold for exploration + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 500 # Increased iterations for thorough fine-tuning + refinement_step_size = 0.0005 # Maintained for fine-tuning + refinement_repulsion_strength = 0.008 # Slightly increased repulsion strength + refinement_boundary_strength = 0.04 # Increased boundary strength + refinement_repulsion_threshold = 0.185 # Distinct threshold for refinement + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/original.py new file mode 100644 index 0000000000000000000000000000000000000000..c3082cb83518797899c2cdebac2b193e20eddd1a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/original.py @@ -0,0 +1,193 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + to create a larger void for the 26th circle. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 + boundary_margin = 0.04 + n = centers.shape[0] + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..7fa0eae7322df1bc428d88d89b3833b1a2005f5f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_65/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_65/results +Run 1/1 completed in 0.74 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.7701437276455079 + public: {'centers_str': ' centers[0] = (0.1000, 0.1000)\n centers[1] = (0.2998, 0.0992)\n centers[2] = (0.5000, 0.0976)\n centers[3] = (0.7002, 0.0992)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0992, 0.2998)\n centers[6] = (0.2953, 0.2953)\n centers[7] = (0.5000, 0.2839)\n centers[8] = (0.7047, 0.2953)\n centers[9] = (0.9008, 0.2998)\n centers[10] = (0.0976, 0.5000)\n centers[11] = (0.2839, 0.5000)\n centers[12] = (0.5000, 0.5000)\n centers[13] = (0.7161, 0.5000)\n centers[14] = (0.9024, 0.5000)\n centers[15] = (0.0992, 0.7002)\n centers[16] = (0.2953, 0.7047)\n centers[17] = (0.5000, 0.7161)\n centers[18] = (0.7047, 0.7047)\n centers[19] = (0.9008, 0.7002)\n centers[20] = (0.1000, 0.9000)\n centers[21] = (0.2998, 0.9008)\n centers[22] = (0.5000, 0.9024)\n centers[23] = (0.7002, 0.9008)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.5000, 0.5000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.7701437276455079} + visualization_path: + execution_time_mean: 0.7355036661028862 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..e6dad83bd1620ab83d0bf98768c8c10c434b8600 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.7701437276455079, + "public": { + "centers_str": " centers[0] = (0.1000, 0.1000)\n centers[1] = (0.2998, 0.0992)\n centers[2] = (0.5000, 0.0976)\n centers[3] = (0.7002, 0.0992)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0992, 0.2998)\n centers[6] = (0.2953, 0.2953)\n centers[7] = (0.5000, 0.2839)\n centers[8] = (0.7047, 0.2953)\n centers[9] = (0.9008, 0.2998)\n centers[10] = (0.0976, 0.5000)\n centers[11] = (0.2839, 0.5000)\n centers[12] = (0.5000, 0.5000)\n centers[13] = (0.7161, 0.5000)\n centers[14] = (0.9024, 0.5000)\n centers[15] = (0.0992, 0.7002)\n centers[16] = (0.2953, 0.7047)\n centers[17] = (0.5000, 0.7161)\n centers[18] = (0.7047, 0.7047)\n centers[19] = (0.9008, 0.7002)\n centers[20] = (0.1000, 0.9000)\n centers[21] = (0.2998, 0.9008)\n centers[22] = (0.5000, 0.9024)\n centers[23] = (0.7002, 0.9008)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.5000, 0.5000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.7701437276455079 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_65/results/packing_viz.png", + "execution_time_mean": 0.7355036661028862, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..b9f405f6e1be5b5f8e2a00f92cd8044c25451551 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_65/search_replace.txt @@ -0,0 +1,127 @@ +The current visualization shows a large central circle surrounded by several very small circles, indicating inefficient use of space in the core of the square. The surrounding circles are also somewhat aligned in a grid, which is often not optimal for dense packing. + +To address these issues, I propose the following changes: + +1. **Central Symmetry for Initial Void**: By shifting the `void_center` to `(0.5, 0.5)` (the true center of the unit square), we introduce a more symmetric initial condition for the 26th circle and the surrounding 5x5 grid. This might lead to a more balanced distribution of forces and prevent one central circle from growing disproportionately large at the expense of its neighbors, as observed in the current visualization. When `void_center` is `(0.5, 0.5)`, the central circle of the initial 5x5 grid (also at `(0.5, 0.5)`) will not be pushed by the Gaussian deformation, as its distance to the `void_center` will be zero. The 26th circle will then be placed at `(0.5, 0.5)`, creating a strong initial overlap that the subsequent relaxation stages will resolve, potentially leading to a denser central packing. + +2. **Distinct and Optimized Repulsion Thresholds**: Re-introducing distinct `repulsion_threshold` values for the exploration and refinement stages, similar to successful prior programs, allows for better control. A slightly larger `exploration_repulsion_threshold` (`0.20`) encourages circles to spread out more initially and interact over a broader range, helping to break the rigid grid structure. A tighter `refinement_repulsion_threshold` (`0.185`) then facilitates denser packing during the fine-tuning phase. + +3. **Increased Iterations and Tuned Forces**: The exploration and refinement stages have been adjusted with parameters from higher-scoring previous iterations. The `exploration_iters`, `exploration_step_size`, `exploration_repulsion_strength`, and `exploration_boundary_strength` are increased to promote more aggressive global rearrangement. Crucially, `refinement_iters` is significantly increased (from 150 to 500) to allow the system ample time to settle into a high-density local optimum with finer adjustments, using also slightly increased `refinement_repulsion_strength` and `refinement_boundary_strength` for more effective settling. These adjustments aim to better utilize the available space, particularly around the central region and near the boundaries, leading to a higher sum of radii. + + +A central void at (0.5, 0.5) ensures symmetry, potentially leading to a more balanced initial distribution of circles around the center and preventing one circle from becoming too large at the expense of its neighbors. + + +<<<<<<< SEARCH + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) +======= + # A central interstitial void at (0.5, 0.5) is a good candidate for symmetry. + void_center = np.array([0.5, 0.5]) +>>>>>>> REPLACE + + + +This edit refines the exploration stage by increasing iterations and force strengths, and introducing a distinct repulsion threshold. These parameters are chosen from previous high-scoring programs to promote more aggressive global rearrangement and break the initial grid symmetry more effectively, encouraging a denser initial packing before refinement. + + +<<<<<<< SEARCH + # Shared parameters for both stages: + repulsion_threshold = 0.185 + boundary_margin = 0.04 + n = centers.shape[0] + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec +======= + # Shared parameters: + boundary_margin = 0.04 + n = centers.shape[0] + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 250 # Increased iterations for better exploration + exploration_step_size = 0.003 # Slightly increased step size + exploration_repulsion_strength = 0.02 # Increased repulsion strength + exploration_boundary_strength = 0.1 # Increased boundary strength + exploration_repulsion_threshold = 0.20 # Distinct threshold for exploration + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec +>>>>>>> REPLACE + + + +This edit optimizes the refinement stage by significantly increasing iterations and tuning force strengths and threshold. More iterations allow for thorough fine-tuning and convergence to a denser local optimum. The distinct repulsion threshold helps achieve tighter packing. These adjustments are based on successful prior programs to maximize the sum of radii. + + +<<<<<<< SEARCH + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec +======= + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 500 # Increased iterations for thorough fine-tuning + refinement_step_size = 0.0005 # Maintained for fine-tuning + refinement_repulsion_strength = 0.008 # Slightly increased repulsion strength + refinement_boundary_strength = 0.04 # Increased boundary strength + refinement_repulsion_threshold = 0.185 # Distinct threshold for refinement + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21f6f767e806249c9dbedc3ae390a80ce53ba833 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..6447c761531cda00a79abac192f1779bb6e79635 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/edit.diff @@ -0,0 +1,183 @@ +--- a/original.py ++++ b/original.py +@@ -1,174 +1,175 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + and applying a two-stage (exploration/refinement) force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + +- # 1. Start with the 25 centers of a 5x5 grid. +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) ++ # 1. Start with the 25 centers of a 5x5 grid, expanded to better utilize edges. ++ x_coords = np.linspace(0.05, 0.95, 5) ++ y_coords = np.linspace(0.05, 0.95, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Define the center of the void where the 26th circle will be placed. +- void_center = np.array([0.4, 0.4]) ++ # 2. Define the center of the void, adjusted for the new grid spacing. ++ # The new central grid points are based on {0.275, 0.5}, so the void is centered. ++ void_center = np.array([0.3875, 0.3875]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void, allowing more room for exploration. + amplitude = 0.05 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to break the initial + # grid structure and find a better global arrangement. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + repulsion_threshold = 0.20 # Increased threshold to encourage movement and interaction. + boundary_margin = 0.04 # Smaller margin to better utilize edges. + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to fine-tune the circle positions and settle into a dense local optimum. + refinement_iters = 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + # Use a slightly smaller repulsion threshold for refinement to allow tighter packing. + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/main.py new file mode 100644 index 0000000000000000000000000000000000000000..93bf0ee54495046f802261c9d7005e9625c2dc62 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/main.py @@ -0,0 +1,175 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + and applying a two-stage (exploration/refinement) force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid, expanded to better utilize edges. + x_coords = np.linspace(0.05, 0.95, 5) + y_coords = np.linspace(0.05, 0.95, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void, adjusted for the new grid spacing. + # The new central grid points are based on {0.275, 0.5}, so the void is centered. + void_center = np.array([0.3875, 0.3875]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void, allowing more room for exploration. + amplitude = 0.05 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to break the initial + # grid structure and find a better global arrangement. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + repulsion_threshold = 0.20 # Increased threshold to encourage movement and interaction. + boundary_margin = 0.04 # Smaller margin to better utilize edges. + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to fine-tune the circle positions and settle into a dense local optimum. + refinement_iters = 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + # Use a slightly smaller repulsion threshold for refinement to allow tighter packing. + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/original.py new file mode 100644 index 0000000000000000000000000000000000000000..cf9fe2e615d0d4c1ad0b452b234bd4ff689e21c6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/original.py @@ -0,0 +1,174 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + and applying a two-stage (exploration/refinement) force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void, allowing more room for exploration. + amplitude = 0.05 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to break the initial + # grid structure and find a better global arrangement. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + repulsion_threshold = 0.20 # Increased threshold to encourage movement and interaction. + boundary_margin = 0.04 # Smaller margin to better utilize edges. + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to fine-tune the circle positions and settle into a dense local optimum. + refinement_iters = 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + # Use a slightly smaller repulsion threshold for refinement to allow tighter packing. + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..1185b2b08c0b84012ef2aa3de73eef3ed3d34dd7 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_66/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_66/results +Run 1/1 completed in 0.69 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.5223056195455915 + public: {'centers_str': ' centers[0] = (0.0498, 0.0498)\n centers[1] = (0.2741, 0.0472)\n centers[2] = (0.5009, 0.0472)\n centers[3] = (0.7252, 0.0498)\n centers[4] = (0.9500, 0.0500)\n centers[5] = (0.0472, 0.2741)\n centers[6] = (0.2542, 0.2542)\n centers[7] = (0.5208, 0.2542)\n centers[8] = (0.7278, 0.2741)\n centers[9] = (0.9500, 0.2750)\n centers[10] = (0.0472, 0.5009)\n centers[11] = (0.2542, 0.5208)\n centers[12] = (0.5208, 0.5208)\n centers[13] = (0.7278, 0.5009)\n centers[14] = (0.9500, 0.5000)\n centers[15] = (0.0498, 0.7252)\n centers[16] = (0.2741, 0.7278)\n centers[17] = (0.5009, 0.7278)\n centers[18] = (0.7252, 0.7252)\n centers[19] = (0.9500, 0.7250)\n centers[20] = (0.0500, 0.9500)\n centers[21] = (0.2750, 0.9500)\n centers[22] = (0.5000, 0.9500)\n centers[23] = (0.7250, 0.9500)\n centers[24] = (0.9500, 0.9500)\n centers[25] = (0.3875, 0.3875)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.5223056195455915} + visualization_path: + execution_time_mean: 0.6875585909001529 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..23ebd4afca0b17fde9946fbea10893872deb1610 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.5223056195455915, + "public": { + "centers_str": " centers[0] = (0.0498, 0.0498)\n centers[1] = (0.2741, 0.0472)\n centers[2] = (0.5009, 0.0472)\n centers[3] = (0.7252, 0.0498)\n centers[4] = (0.9500, 0.0500)\n centers[5] = (0.0472, 0.2741)\n centers[6] = (0.2542, 0.2542)\n centers[7] = (0.5208, 0.2542)\n centers[8] = (0.7278, 0.2741)\n centers[9] = (0.9500, 0.2750)\n centers[10] = (0.0472, 0.5009)\n centers[11] = (0.2542, 0.5208)\n centers[12] = (0.5208, 0.5208)\n centers[13] = (0.7278, 0.5009)\n centers[14] = (0.9500, 0.5000)\n centers[15] = (0.0498, 0.7252)\n centers[16] = (0.2741, 0.7278)\n centers[17] = (0.5009, 0.7278)\n centers[18] = (0.7252, 0.7252)\n centers[19] = (0.9500, 0.7250)\n centers[20] = (0.0500, 0.9500)\n centers[21] = (0.2750, 0.9500)\n centers[22] = (0.5000, 0.9500)\n centers[23] = (0.7250, 0.9500)\n centers[24] = (0.9500, 0.9500)\n centers[25] = (0.3875, 0.3875)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.5223056195455915 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_66/results/packing_viz.png", + "execution_time_mean": 0.6875585909001529, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..0311487e78c380c002d3cccb563f05e47f5f43c2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_66/search_replace.txt @@ -0,0 +1,36 @@ + +expand_initial_grid_and_void + + + +Based on the visual analysis, the current packing underutilizes the space at the corners and along the edges of the unit square. The circles on the periphery are large, but there are significant gaps between them and the boundary. This is likely because the initial 5x5 grid, defined by `linspace(0.1, 0.9, 5)`, places the outermost circles too far from the edges (at a distance of 0.1). + +To address this, I propose expanding the initial grid towards the boundaries. By changing the grid definition to `linspace(0.05, 0.95, 5)`, the outermost circles will start at a distance of 0.05 from the edges. This gives the force-directed relaxation algorithm a starting point that has a higher potential for good edge and corner utilization, encouraging the circles to pack tightly against the boundaries. + +As this change modifies the grid coordinates, the position of the central interstitial void for the 26th circle must also be updated to maintain a consistent starting strategy. The original void at `(0.4, 0.4)` was the center of the square formed by grid points at `(0.3, 0.3)`, `(0.3, 0.5)`, `(0.5, 0.3)`, and `(0.5, 0.5)`. With the new grid coordinates (`0.05, 0.275, 0.5, 0.725, 0.95`), the four central points are now defined by x and y coordinates from `{0.275, 0.5}`. The new void center is therefore recalculated as `( (0.275+0.5)/2, (0.275+0.5)/2 )`, which is `(0.3875, 0.3875)`. + +This combined change directly targets a clear inefficiency visible in the packing, providing a more promising initial configuration for achieving a denser final arrangement. + + + +<<<<<<< SEARCH + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + void_center = np.array([0.4, 0.4]) +======= + # 1. Start with the 25 centers of a 5x5 grid, expanded to better utilize edges. + x_coords = np.linspace(0.05, 0.95, 5) + y_coords = np.linspace(0.05, 0.95, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void, adjusted for the new grid spacing. + # The new central grid points are based on {0.275, 0.5}, so the void is centered. + void_center = np.array([0.3875, 0.3875]) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e24344218615a917cd7be2fc9502b08e4dc0547 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..2e82bc821153bff45801f310405e10eab87d55f7 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_67/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_67/results +Run 1/1 completed in 0.78 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.955888696162715 + public: {'centers_str': ' centers[0] = (0.0982, 0.0982)\n centers[1] = (0.2992, 0.0925)\n centers[2] = (0.5008, 0.0924)\n centers[3] = (0.7006, 0.0982)\n centers[4] = (0.9013, 0.0988)\n centers[5] = (0.0925, 0.2992)\n centers[6] = (0.2793, 0.2793)\n centers[7] = (0.5206, 0.2793)\n centers[8] = (0.7058, 0.2992)\n centers[9] = (0.9020, 0.2999)\n centers[10] = (0.0924, 0.5008)\n centers[11] = (0.2793, 0.5206)\n centers[12] = (0.5206, 0.5206)\n centers[13] = (0.7058, 0.5008)\n centers[14] = (0.9020, 0.5000)\n centers[15] = (0.0982, 0.7006)\n centers[16] = (0.2992, 0.7058)\n centers[17] = (0.5008, 0.7058)\n centers[18] = (0.7006, 0.7006)\n centers[19] = (0.9013, 0.7001)\n centers[20] = (0.0988, 0.9013)\n centers[21] = (0.2999, 0.9020)\n centers[22] = (0.5000, 0.9020)\n centers[23] = (0.7001, 0.9013)\n centers[24] = (0.9012, 0.9012)\n centers[25] = (0.4000, 0.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.955888696162715} + visualization_path: + execution_time_mean: 0.7775514661334455 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..48143d09fabe472e493bc91e08b7f5d11126ae25 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.955888696162715, + "public": { + "centers_str": " centers[0] = (0.0982, 0.0982)\n centers[1] = (0.2992, 0.0925)\n centers[2] = (0.5008, 0.0924)\n centers[3] = (0.7006, 0.0982)\n centers[4] = (0.9013, 0.0988)\n centers[5] = (0.0925, 0.2992)\n centers[6] = (0.2793, 0.2793)\n centers[7] = (0.5206, 0.2793)\n centers[8] = (0.7058, 0.2992)\n centers[9] = (0.9020, 0.2999)\n centers[10] = (0.0924, 0.5008)\n centers[11] = (0.2793, 0.5206)\n centers[12] = (0.5206, 0.5206)\n centers[13] = (0.7058, 0.5008)\n centers[14] = (0.9020, 0.5000)\n centers[15] = (0.0982, 0.7006)\n centers[16] = (0.2992, 0.7058)\n centers[17] = (0.5008, 0.7058)\n centers[18] = (0.7006, 0.7006)\n centers[19] = (0.9013, 0.7001)\n centers[20] = (0.0988, 0.9013)\n centers[21] = (0.2999, 0.9020)\n centers[22] = (0.5000, 0.9020)\n centers[23] = (0.7001, 0.9013)\n centers[24] = (0.9012, 0.9012)\n centers[25] = (0.4000, 0.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.955888696162715 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_67/results/packing_viz.png", + "execution_time_mean": 0.7775514661334455, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f017cab364f63b84ea65cc3431915c3f8d2aa571 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..28632d0c3ba512d6b4a543a6068e1803b76c4e98 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/edit.diff @@ -0,0 +1,230 @@ +--- a/original.py ++++ b/original.py +@@ -1,174 +1,202 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid +- and applying a two-stage (exploration/refinement) force-directed relaxation. ++ from an asymmetric void and applying a three-stage (exploration/refinement/annealing) ++ force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Define the center of the void where the 26th circle will be placed. +- void_center = np.array([0.4, 0.4]) +- +- # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. ++ # 2. Define an ASYMMETRIC center for the void. ++ # Instead of (0.4, 0.4), using (0.4, 0.2) breaks the initial symmetry, ++ # allowing the relaxation to find a less ordered and denser packing. ++ void_center = np.array([0.4, 0.2]) ++ ++ # 3. Deform the 25 grid points with a Gaussian push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + +- # Increased amplitude to create a larger initial void, allowing more room for exploration. +- amplitude = 0.05 ++ # Increased amplitude to create a larger initial void. ++ amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + +- # 4. Stage 1: High-Energy Exploration +- # This stage uses strong forces and a large step size to break the initial +- # grid structure and find a better global arrangement. +- exploration_iters = 250 ++ boundary_margin = 0.04 ++ ++ # 4. Stage 1: High-Energy Exploration ("Shaking") ++ # Increased iterations and strength to break the grid structure more effectively. ++ exploration_iters = 300 + exploration_step_size = 0.003 +- exploration_repulsion_strength = 0.02 ++ exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 +- repulsion_threshold = 0.20 # Increased threshold to encourage movement and interaction. +- boundary_margin = 0.04 # Smaller margin to better utilize edges. ++ exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist ++ if 0 < dist < exploration_repulsion_threshold: ++ force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + +- # 5. Stage 2: Low-Energy Refinement +- # This stage uses more iterations with weaker forces and a smaller step size +- # to fine-tune the circle positions and settle into a dense local optimum. +- refinement_iters = 400 ++ # 5. Stage 2: Low-Energy Refinement ("Settling") ++ # A longer settling period with moderate forces to find a good basin of attraction. ++ refinement_iters = 500 + refinement_step_size = 0.0005 +- refinement_repulsion_strength = 0.008 ++ refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 +- +- # Use a slightly smaller repulsion threshold for refinement to allow tighter packing. + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) +- +- # 6. Compute maximum valid radii for the refined configuration. ++ ++ # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") ++ # A new stage for final micro-adjustments with very weak forces and many iterations. ++ annealing_iters = 800 ++ annealing_step_size = 0.0001 ++ annealing_repulsion_strength = 0.004 ++ annealing_boundary_strength = 0.02 ++ annealing_repulsion_threshold = 0.18 # Even tighter threshold for final packing ++ ++ for _ in range(annealing_iters): ++ forces = np.zeros_like(centers) ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < annealing_repulsion_threshold: ++ force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist ++ force_vec = force_mag * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) ++ centers += annealing_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/main.py new file mode 100644 index 0000000000000000000000000000000000000000..d9e17356508bbf96099a9b6c90090e5f4ff96760 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/main.py @@ -0,0 +1,202 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Instead of (0.4, 0.4), using (0.4, 0.2) breaks the initial symmetry, + # allowing the relaxation to find a less ordered and denser packing. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + boundary_margin = 0.04 + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # A new stage for final micro-adjustments with very weak forces and many iterations. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 # Even tighter threshold for final packing + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/original.py new file mode 100644 index 0000000000000000000000000000000000000000..cf9fe2e615d0d4c1ad0b452b234bd4ff689e21c6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/original.py @@ -0,0 +1,174 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + and applying a two-stage (exploration/refinement) force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void, allowing more room for exploration. + amplitude = 0.05 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to break the initial + # grid structure and find a better global arrangement. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + repulsion_threshold = 0.20 # Increased threshold to encourage movement and interaction. + boundary_margin = 0.04 # Smaller margin to better utilize edges. + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to fine-tune the circle positions and settle into a dense local optimum. + refinement_iters = 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + # Use a slightly smaller repulsion threshold for refinement to allow tighter packing. + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..6580c2f80b4eae4078413c3772a1aa92e7ce0812 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_68/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_68/results +Run 1/1 completed in 1.71 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9808569554223658 + 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} + private: {'reported_sum_of_radii': 1.9808569554223658} + visualization_path: + execution_time_mean: 1.712255713995546 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..96c6fc7e613baf10e8f2411a7ac76bccc7c895cd --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9808569554223658, + "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 + }, + "private": { + "reported_sum_of_radii": 1.9808569554223658 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_68/results/packing_viz.png", + "execution_time_mean": 1.712255713995546, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..259b41229806baa9e63c8b00d4060bda1eb35683 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_68/rewrite.txt @@ -0,0 +1,193 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Instead of (0.4, 0.4), using (0.4, 0.2) breaks the initial symmetry, + # allowing the relaxation to find a less ordered and denser packing. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + boundary_margin = 0.04 + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # A new stage for final micro-adjustments with very weak forces and many iterations. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 # Even tighter threshold for final packing + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..920f784a285256eb12b518f196650b11e51ef381 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..452e0688a09b12c339bca88e4a9910df920e6821 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/edit.diff @@ -0,0 +1,216 @@ +--- a/original.py ++++ b/original.py +@@ -1,184 +1,188 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.05 # The maximum distance to push a circle. Increased to create a larger void. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This approach uses a high-energy "exploration" phase to break symmetry + # and find a good general configuration, followed by a low-energy + # "refinement" phase to fine-tune the positions. + + # Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to quickly move circles + # out of the initial grid structure and explore new arrangements. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 +- repulsion_threshold = 0.19 # A common threshold for both stages ++ exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement ++ refinement_repulsion_threshold = 0.185 # Smaller threshold for tight packing + boundary_margin = 0.04 # Use a smaller margin to utilize edge space better + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist ++ if 0 < dist < exploration_repulsion_threshold: ++ force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_mag = refinement_repulsion_strength * (repulsion_threshold - dist) / dist ++ if 0 < dist < refinement_repulsion_threshold: ++ force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This version +- iteratively resolves conflicts until convergence for a more accurate result. ++ such that they don't overlap and stay within the unit square. This is ++ a robust iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.zeros(n) + +- # First, limit by distance to square borders ++ # Initialize radii based on distance to the square's boundaries. + for i in range(n): + x, y = centers[i] +- radii[i] = min(x, y, 1 - x, 1 - y) ++ radii[i] = min(x, 1 - x, y, 1 - y) + +- # Iteratively limit by distance to other circles, allowing constraints to propagate +- for _ in range(300): # Iterate to ensure convergence +- changes_made = False ++ # Iteratively resolve overlaps between circles until no more changes occur. ++ # A high number of iterations and tight tolerance ensures convergence. ++ for _ in range(500): ++ changed_in_pass = False ++ # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + +- # If current radii cause overlap +- if radii[i] + radii[j] > dist: ++ # If they overlap (with a small tolerance for floating point math) ++ if radii[i] + radii[j] > dist + 1e-12: ++ # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] +- if sum_r > 1e-9: # Avoid division by zero for coincident centers +- # Scale both radii proportionally to resolve overlap ++ if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r +- ri_new = radii[i] * scale +- rj_new = radii[j] * scale ++ radii[i] *= scale ++ radii[j] *= scale ++ else: # If both radii are already ~0, ensure they are exactly 0 ++ radii[i] = 0 ++ radii[j] = 0 + +- # Check for significant change to set the flag +- if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: +- radii[i] = ri_new +- radii[j] = rj_new +- changes_made = True +- if not changes_made: +- break # Exit early if the configuration is stable ++ changed_in_pass = True ++ ++ # If a full pass resulted in no changes, the packing is stable. ++ if not changed_in_pass: ++ break + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/main.py new file mode 100644 index 0000000000000000000000000000000000000000..5bbac6fb380ac9d4bf145e59650ae421274ca539 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/main.py @@ -0,0 +1,188 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.05 # The maximum distance to push a circle. Increased to create a larger void. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This approach uses a high-energy "exploration" phase to break symmetry + # and find a good general configuration, followed by a low-energy + # "refinement" phase to fine-tune the positions. + + # Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to quickly move circles + # out of the initial grid structure and explore new arrangements. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement + refinement_repulsion_threshold = 0.185 # Smaller threshold for tight packing + boundary_margin = 0.04 # Use a smaller margin to utilize edge space better + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + a robust iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.zeros(n) + + # Initialize radii based on distance to the square's boundaries. + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations and tight tolerance ensures convergence. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/original.py new file mode 100644 index 0000000000000000000000000000000000000000..14a7335cae04ef736e073b1b9e18ae4959eeab90 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/original.py @@ -0,0 +1,184 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room. + deformed_centers_25 = np.copy(base_centers_25) + + # Hyperparameters for the Gaussian push: + amplitude = 0.05 # The maximum distance to push a circle. Increased to create a larger void. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the square, although the push is gentle. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This approach uses a high-energy "exploration" phase to break symmetry + # and find a good general configuration, followed by a low-energy + # "refinement" phase to fine-tune the positions. + + # Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to quickly move circles + # out of the initial grid structure and explore new arrangements. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + repulsion_threshold = 0.19 # A common threshold for both stages + boundary_margin = 0.04 # Use a smaller margin to utilize edge space better + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.zeros(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..db884d73b57c73f79f7de3116ec73cd0c265a37d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_69/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_69/results +Run 1/1 completed in 0.93 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9676244125863362 + public: {'centers_str': ' centers[0] = (0.0993, 0.0993)\n centers[1] = (0.2985, 0.0936)\n centers[2] = (0.5015, 0.0936)\n centers[3] = (0.7007, 0.0993)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0936, 0.2985)\n centers[6] = (0.2768, 0.2768)\n centers[7] = (0.5232, 0.2768)\n centers[8] = (0.7060, 0.2985)\n centers[9] = (0.9006, 0.3000)\n centers[10] = (0.0936, 0.5015)\n centers[11] = (0.2768, 0.5232)\n centers[12] = (0.5232, 0.5232)\n centers[13] = (0.7060, 0.5015)\n centers[14] = (0.9006, 0.5000)\n centers[15] = (0.0993, 0.7007)\n centers[16] = (0.2985, 0.7060)\n centers[17] = (0.5015, 0.7060)\n centers[18] = (0.7007, 0.7007)\n centers[19] = (0.9001, 0.7000)\n centers[20] = (0.1000, 0.9001)\n centers[21] = (0.3000, 0.9006)\n centers[22] = (0.5000, 0.9006)\n centers[23] = (0.7000, 0.9001)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9676244125863362} + visualization_path: + execution_time_mean: 0.9301674352027476 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..f8b4a6a66e5272addd07e24d3783c3e125afd101 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9676244125863362, + "public": { + "centers_str": " centers[0] = (0.0993, 0.0993)\n centers[1] = (0.2985, 0.0936)\n centers[2] = (0.5015, 0.0936)\n centers[3] = (0.7007, 0.0993)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0936, 0.2985)\n centers[6] = (0.2768, 0.2768)\n centers[7] = (0.5232, 0.2768)\n centers[8] = (0.7060, 0.2985)\n centers[9] = (0.9006, 0.3000)\n centers[10] = (0.0936, 0.5015)\n centers[11] = (0.2768, 0.5232)\n centers[12] = (0.5232, 0.5232)\n centers[13] = (0.7060, 0.5015)\n centers[14] = (0.9006, 0.5000)\n centers[15] = (0.0993, 0.7007)\n centers[16] = (0.2985, 0.7060)\n centers[17] = (0.5015, 0.7060)\n centers[18] = (0.7007, 0.7007)\n centers[19] = (0.9001, 0.7000)\n centers[20] = (0.1000, 0.9001)\n centers[21] = (0.3000, 0.9006)\n centers[22] = (0.5000, 0.9006)\n centers[23] = (0.7000, 0.9001)\n centers[24] = (0.9000, 0.9000)\n centers[25] = (0.4000, 0.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9676244125863362 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_69/results/packing_viz.png", + "execution_time_mean": 0.9301674352027476, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f76f40adff2a0b7c0232d735c87521fcf19584c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_69/search_replace.txt @@ -0,0 +1,198 @@ + +dual_threshold_relaxation_and_robust_radii + + + +Based on the visual feedback, the current packing shows an inefficiency in the central region, where four circles are compressed to a very small size around the main central circle. This suggests the relaxation process can be improved. My changes address this in two ways: + +1. **Dual-Threshold Relaxation**: I'm modifying the force-directed relaxation to use two distinct `repulsion_threshold` values. A larger threshold (`0.20`) is used during the initial "exploration" stage to encourage more significant rearrangements and break out of suboptimal local minima (like the one trapping the small central circles). A smaller, tighter threshold (`0.185`) is then used for the "refinement" stage to allow the circles to settle into a denser final configuration. This two-stage approach with different energy levels was successful in previous high-scoring versions. + +2. **Robust Radii Computation**: I am replacing the current `compute_max_radii` function with a more robust and accurate implementation from a previous high-scoring version. This version uses a higher number of maximum iterations (500), a tighter floating-point tolerance (`1e-12`), and a more direct convergence check (`changed_in_pass`). This ensures that the radii we calculate for any given arrangement of centers are as large as possible and accurately reflect the packing's quality, which is critical for guiding the evolution towards better solutions. + + + +<<<<<<< SEARCH + repulsion_threshold = 0.19 # A common threshold for both stages + boundary_margin = 0.04 # Use a smaller margin to utilize edge space better + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec +======= + exploration_repulsion_threshold = 0.20 # Larger threshold for broad rearrangement + refinement_repulsion_threshold = 0.185 # Smaller threshold for tight packing + boundary_margin = 0.04 # Use a smaller margin to utilize edge space better + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to settle the circles into a dense, stable local optimum. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec +>>>>>>> REPLACE +<<<<<<< SEARCH +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.zeros(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + radii[i] = min(x, y, 1 - x, 1 - y) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii +======= +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + a robust iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.zeros(n) + + # Initialize radii based on distance to the square's boundaries. + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations and tight tolerance ensures convergence. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..16c0b0ebe0482d0c3d3175aad8543ac390c5dd31 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..45520500cd2b3b7f2ecce1f4b4d4ba0c36e8b8a4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/edit.diff @@ -0,0 +1,166 @@ +--- a/original.py ++++ b/original.py +@@ -1,135 +1,109 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + +- # Place circles in a staggered grid pattern to improve density +- # This pattern aims for a more uniform distribution than concentric rings ++ # A more symmetric and compact grid layout inspired by dense packings. ++ # The previous layout was asymmetric ([5,6,5,6,4]) and had poor vertical spacing. ++ num_rows = 5 ++ # This row count distribution is symmetric and places more circles in the center. ++ row_counts = [5, 5, 6, 5, 5] # Total: 5+5+6+5+5 = 26 circles + +- num_rows = 5 # Number of rows for the staggered grid +- # Distribute 26 circles into these rows, with some staggering +- # This specific distribution attempts to maximize space utilization +- row_counts = [5, 6, 5, 6, 4] # Total: 5 + 6 + 5 + 6 + 4 = 26 circles ++ # Use tighter vertical packing. The previous method left large gaps (1/6) at top/bottom. ++ # This linspace packs rows from y=0.1 to y=0.9, consistent with a radius of 0.1 for a 5x5 grid. ++ y_coords = np.linspace(0.1, 0.9, num_rows) + +- # Calculate vertical spacing for rows. Centers will be placed at y_start + (row_idx + 0.5) * y_interval +- y_interval = 1.0 / (num_rows + 1) +- +- # Determine the maximum number of circles in any row to set a consistent x-shift for staggering +- max_circles_in_row = max(row_counts) # This is 6 ++ # Margin for x coordinates, consistent with y_coords margins. ++ margin = 0.1 + + idx = 0 +- for r_idx, count_in_row in enumerate(row_counts): +- current_y = (r_idx + 1) * y_interval # Centers are at y_interval * 1, 2, ..., num_rows ++ for r_idx, count in enumerate(row_counts): ++ y = y_coords[r_idx] + +- # Define x-positions for circles in the current row +- # Start with a small margin (e.g., 0.05) to allow for some radius +- initial_x_margin = 0.05 +- x_positions_for_row = np.linspace(initial_x_margin, 1.0 - initial_x_margin, count_in_row) ++ # Simplified staggering logic. ++ # Odd rows are shifted to sit in the gaps of even rows. ++ if r_idx % 2 == 0: # Even rows (0, 2, 4) ++ # Place circles edge-to-edge within the margins ++ x_coords = np.linspace(margin, 1.0 - margin, count) ++ else: # Odd rows (1, 3) are staggered ++ # Create space at the ends to shift the circles. ++ # linspace over (count+2) points and skipping the first and last ++ # achieves a simple and effective stagger. ++ x_coords = np.linspace(margin, 1.0 - margin, count + 2)[1:-1] + +- # Apply staggering to every other row +- if r_idx % 2 == 1: # Stagger rows 1 and 3 (0-indexed) +- # Shift by half of the average x spacing, derived from the row with max circles +- # This makes the staggering more consistent +- shift_amount = (1.0 / (max_circles_in_row + 1)) / 2.0 +- x_positions_for_row += shift_amount ++ for x in x_coords: ++ if idx < n: ++ centers[idx] = [x, y] ++ idx += 1 + +- # After shifting, ensure centers remain within the acceptable range [initial_x_margin, 1-initial_x_margin] +- # Rescale if necessary to keep them contained and maintain symmetry +- min_x_val = np.min(x_positions_for_row) +- max_x_val = np.max(x_positions_for_row) +- +- # If the shifted row goes outside the initial margins, rescale it to fit +- if min_x_val < initial_x_margin or max_x_val > (1.0 - initial_x_margin): +- target_range_width = (1.0 - initial_x_margin) - initial_x_margin +- current_range_width = max_x_val - min_x_val +- +- # Avoid division by zero if all circles are at the same point (shouldn't happen here) +- if current_range_width > 1e-6: +- scale_factor = target_range_width / current_range_width +- x_positions_for_row = (x_positions_for_row - min_x_val) * scale_factor + initial_x_margin +- else: # Fallback for extreme cases, just center them +- x_positions_for_row = np.full_like(x_positions_for_row, 0.5) +- +- # Populate the centers array +- for x_val in x_positions_for_row: +- if idx < n: # Safety check, should always be true here +- centers[idx] = [x_val, current_y] +- idx += 1 +- else: +- break # All circles placed +- if idx >= n: +- break +- +- # Clip to ensure everything is inside the unit square. Our placement aims to keep +- # centers within [0.05, 0.95], which is stricter than [0.01, 0.99], so this clip +- # will primarily serve as a safety measure and honor the original code's intent. +- centers = np.clip(centers, 0.01, 0.99) ++ # The placement logic naturally keeps centers within the square. ++ # No clipping is necessary, as radii calculation correctly handles boundaries. + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/main.py new file mode 100644 index 0000000000000000000000000000000000000000..64494262aa335723d036acc4da1821ec21a083be --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/main.py @@ -0,0 +1,109 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # A more symmetric and compact grid layout inspired by dense packings. + # The previous layout was asymmetric ([5,6,5,6,4]) and had poor vertical spacing. + num_rows = 5 + # This row count distribution is symmetric and places more circles in the center. + row_counts = [5, 5, 6, 5, 5] # Total: 5+5+6+5+5 = 26 circles + + # Use tighter vertical packing. The previous method left large gaps (1/6) at top/bottom. + # This linspace packs rows from y=0.1 to y=0.9, consistent with a radius of 0.1 for a 5x5 grid. + y_coords = np.linspace(0.1, 0.9, num_rows) + + # Margin for x coordinates, consistent with y_coords margins. + margin = 0.1 + + idx = 0 + for r_idx, count in enumerate(row_counts): + y = y_coords[r_idx] + + # Simplified staggering logic. + # Odd rows are shifted to sit in the gaps of even rows. + if r_idx % 2 == 0: # Even rows (0, 2, 4) + # Place circles edge-to-edge within the margins + x_coords = np.linspace(margin, 1.0 - margin, count) + else: # Odd rows (1, 3) are staggered + # Create space at the ends to shift the circles. + # linspace over (count+2) points and skipping the first and last + # achieves a simple and effective stagger. + x_coords = np.linspace(margin, 1.0 - margin, count + 2)[1:-1] + + for x in x_coords: + if idx < n: + centers[idx] = [x, y] + idx += 1 + + # The placement logic naturally keeps centers within the square. + # No clipping is necessary, as radii calculation correctly handles boundaries. + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/original.py new file mode 100644 index 0000000000000000000000000000000000000000..27c7514b6f120e1038493e95caa4b98ae5de86b4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/original.py @@ -0,0 +1,135 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii, sum_of_radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + sum_of_radii: Sum of all radii + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Place circles in a staggered grid pattern to improve density + # This pattern aims for a more uniform distribution than concentric rings + + num_rows = 5 # Number of rows for the staggered grid + # Distribute 26 circles into these rows, with some staggering + # This specific distribution attempts to maximize space utilization + row_counts = [5, 6, 5, 6, 4] # Total: 5 + 6 + 5 + 6 + 4 = 26 circles + + # Calculate vertical spacing for rows. Centers will be placed at y_start + (row_idx + 0.5) * y_interval + y_interval = 1.0 / (num_rows + 1) + + # Determine the maximum number of circles in any row to set a consistent x-shift for staggering + max_circles_in_row = max(row_counts) # This is 6 + + idx = 0 + for r_idx, count_in_row in enumerate(row_counts): + current_y = (r_idx + 1) * y_interval # Centers are at y_interval * 1, 2, ..., num_rows + + # Define x-positions for circles in the current row + # Start with a small margin (e.g., 0.05) to allow for some radius + initial_x_margin = 0.05 + x_positions_for_row = np.linspace(initial_x_margin, 1.0 - initial_x_margin, count_in_row) + + # Apply staggering to every other row + if r_idx % 2 == 1: # Stagger rows 1 and 3 (0-indexed) + # Shift by half of the average x spacing, derived from the row with max circles + # This makes the staggering more consistent + shift_amount = (1.0 / (max_circles_in_row + 1)) / 2.0 + x_positions_for_row += shift_amount + + # After shifting, ensure centers remain within the acceptable range [initial_x_margin, 1-initial_x_margin] + # Rescale if necessary to keep them contained and maintain symmetry + min_x_val = np.min(x_positions_for_row) + max_x_val = np.max(x_positions_for_row) + + # If the shifted row goes outside the initial margins, rescale it to fit + if min_x_val < initial_x_margin or max_x_val > (1.0 - initial_x_margin): + target_range_width = (1.0 - initial_x_margin) - initial_x_margin + current_range_width = max_x_val - min_x_val + + # Avoid division by zero if all circles are at the same point (shouldn't happen here) + if current_range_width > 1e-6: + scale_factor = target_range_width / current_range_width + x_positions_for_row = (x_positions_for_row - min_x_val) * scale_factor + initial_x_margin + else: # Fallback for extreme cases, just center them + x_positions_for_row = np.full_like(x_positions_for_row, 0.5) + + # Populate the centers array + for x_val in x_positions_for_row: + if idx < n: # Safety check, should always be true here + centers[idx] = [x_val, current_y] + idx += 1 + else: + break # All circles placed + if idx >= n: + break + + # Clip to ensure everything is inside the unit square. Our placement aims to keep + # centers within [0.05, 0.95], which is stricter than [0.01, 0.99], so this clip + # will primarily serve as a safety measure and honor the original code's intent. + centers = np.clip(centers, 0.01, 0.99) + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + for i in range(n): + x, y = centers[i] + # Distance to borders + radii[i] = min(x, y, 1 - x, 1 - y) + + # Then, limit by distance to other circles + # Each pair of circles with centers at distance d can have + # sum of radii at most d to avoid overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.sqrt(np.sum((centers[i] - centers[j]) ** 2)) + + # If current radii would cause overlap + if radii[i] + radii[j] > dist: + # Scale both radii proportionally + scale = dist / (radii[i] + radii[j]) + radii[i] *= scale + radii[j] *= scale + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..ab71db1504cd317c4d906af1f2696e119c12b0a2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_7/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_7/results +Run 1/1 completed in 0.00 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.5087272232242328 + 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.2333, 0.3000)\n centers[6] = (0.3667, 0.3000)\n centers[7] = (0.5000, 0.3000)\n centers[8] = (0.6333, 0.3000)\n centers[9] = (0.7667, 0.3000)\n centers[10] = (0.1000, 0.5000)\n centers[11] = (0.2600, 0.5000)\n centers[12] = (0.4200, 0.5000)\n centers[13] = (0.5800, 0.5000)\n centers[14] = (0.7400, 0.5000)\n centers[15] = (0.9000, 0.5000)\n centers[16] = (0.2333, 0.7000)\n centers[17] = (0.3667, 0.7000)\n centers[18] = (0.5000, 0.7000)\n centers[19] = (0.6333, 0.7000)\n centers[20] = (0.7667, 0.7000)\n centers[21] = (0.1000, 0.9000)\n centers[22] = (0.3000, 0.9000)\n centers[23] = (0.5000, 0.9000)\n centers[24] = (0.7000, 0.9000)\n centers[25] = (0.9000, 0.9000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.5087272232242328} + visualization_path: + execution_time_mean: 0.002166982274502516 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..6f151dcb66bbe80252aa620612a1b239801df66b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.5087272232242328, + "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.2333, 0.3000)\n centers[6] = (0.3667, 0.3000)\n centers[7] = (0.5000, 0.3000)\n centers[8] = (0.6333, 0.3000)\n centers[9] = (0.7667, 0.3000)\n centers[10] = (0.1000, 0.5000)\n centers[11] = (0.2600, 0.5000)\n centers[12] = (0.4200, 0.5000)\n centers[13] = (0.5800, 0.5000)\n centers[14] = (0.7400, 0.5000)\n centers[15] = (0.9000, 0.5000)\n centers[16] = (0.2333, 0.7000)\n centers[17] = (0.3667, 0.7000)\n centers[18] = (0.5000, 0.7000)\n centers[19] = (0.6333, 0.7000)\n centers[20] = (0.7667, 0.7000)\n centers[21] = (0.1000, 0.9000)\n centers[22] = (0.3000, 0.9000)\n centers[23] = (0.5000, 0.9000)\n centers[24] = (0.7000, 0.9000)\n centers[25] = (0.9000, 0.9000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.5087272232242328 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_7/results/packing_viz.png", + "execution_time_mean": 0.002166982274502516, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..5e85d3cb8fd0f1a3c056094a16751af652c433e1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_7/search_replace.txt @@ -0,0 +1,136 @@ + +symmetric_denser_grid + + + +The current circle arrangement, based on visual analysis, suffers from several inefficiencies: +1. **Asymmetric Pattern:** The row distribution `[5, 6, 5, 6, 4]` is unbalanced, leading to irregular spacing and wasted potential. +2. **Poor Vertical Space Utilization:** The vertical spacing `y_interval = 1.0 / (num_rows + 1)` leaves large empty bands at the top and bottom of the square, significantly reducing the available area for the circles. +3. **Complex and Inefficient Staggering:** The logic for staggering rows is overly complicated, involving shifting and rescaling, which doesn't guarantee an optimal or even a good arrangement. + +To address these issues, I propose a complete redesign of the `construct_packing` logic with a focus on symmetry, density, and simplicity: + +1. **Symmetric Row Distribution:** I am changing the row counts to `[5, 5, 6, 5, 5]`. This pattern is symmetric around the horizontal centerline and places more circles in the middle where there is more room away from the vertical boundaries. +2. **Tighter Vertical Packing:** I'm replacing the gappy vertical spacing with `np.linspace(0.1, 0.9, num_rows)`. This packs the rows more tightly, significantly increasing the vertical space available for circles to grow. The `0.1` margin is inspired by the optimal packing of 25 circles (a 5x5 grid), where centers are at `0.1, 0.3, ..., 0.9`. +3. **Simplified Staggering:** I'm implementing a much cleaner staggering method. Even-indexed rows are placed normally, while odd-indexed rows are shifted by using `np.linspace` to generate more points than needed and then selecting the interior ones, effectively creating a staggered offset. + +This new approach creates a more uniform, dense, and structurally sound initial arrangement, which should allow the `compute_max_radii` function to find a solution with a significantly larger sum of radii. + + + +<<<<<<< SEARCH + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # Place circles in a staggered grid pattern to improve density + # This pattern aims for a more uniform distribution than concentric rings + + num_rows = 5 # Number of rows for the staggered grid + # Distribute 26 circles into these rows, with some staggering + # This specific distribution attempts to maximize space utilization + row_counts = [5, 6, 5, 6, 4] # Total: 5 + 6 + 5 + 6 + 4 = 26 circles + + # Calculate vertical spacing for rows. Centers will be placed at y_start + (row_idx + 0.5) * y_interval + y_interval = 1.0 / (num_rows + 1) + + # Determine the maximum number of circles in any row to set a consistent x-shift for staggering + max_circles_in_row = max(row_counts) # This is 6 + + idx = 0 + for r_idx, count_in_row in enumerate(row_counts): + current_y = (r_idx + 1) * y_interval # Centers are at y_interval * 1, 2, ..., num_rows + + # Define x-positions for circles in the current row + # Start with a small margin (e.g., 0.05) to allow for some radius + initial_x_margin = 0.05 + x_positions_for_row = np.linspace(initial_x_margin, 1.0 - initial_x_margin, count_in_row) + + # Apply staggering to every other row + if r_idx % 2 == 1: # Stagger rows 1 and 3 (0-indexed) + # Shift by half of the average x spacing, derived from the row with max circles + # This makes the staggering more consistent + shift_amount = (1.0 / (max_circles_in_row + 1)) / 2.0 + x_positions_for_row += shift_amount + + # After shifting, ensure centers remain within the acceptable range [initial_x_margin, 1-initial_x_margin] + # Rescale if necessary to keep them contained and maintain symmetry + min_x_val = np.min(x_positions_for_row) + max_x_val = np.max(x_positions_for_row) + + # If the shifted row goes outside the initial margins, rescale it to fit + if min_x_val < initial_x_margin or max_x_val > (1.0 - initial_x_margin): + target_range_width = (1.0 - initial_x_margin) - initial_x_margin + current_range_width = max_x_val - min_x_val + + # Avoid division by zero if all circles are at the same point (shouldn't happen here) + if current_range_width > 1e-6: + scale_factor = target_range_width / current_range_width + x_positions_for_row = (x_positions_for_row - min_x_val) * scale_factor + initial_x_margin + else: # Fallback for extreme cases, just center them + x_positions_for_row = np.full_like(x_positions_for_row, 0.5) + + # Populate the centers array + for x_val in x_positions_for_row: + if idx < n: # Safety check, should always be true here + centers[idx] = [x_val, current_y] + idx += 1 + else: + break # All circles placed + if idx >= n: + break + + # Clip to ensure everything is inside the unit square. Our placement aims to keep + # centers within [0.05, 0.95], which is stricter than [0.01, 0.99], so this clip + # will primarily serve as a safety measure and honor the original code's intent. + centers = np.clip(centers, 0.01, 0.99) + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii +======= + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # A more symmetric and compact grid layout inspired by dense packings. + # The previous layout was asymmetric ([5,6,5,6,4]) and had poor vertical spacing. + num_rows = 5 + # This row count distribution is symmetric and places more circles in the center. + row_counts = [5, 5, 6, 5, 5] # Total: 5+5+6+5+5 = 26 circles + + # Use tighter vertical packing. The previous method left large gaps (1/6) at top/bottom. + # This linspace packs rows from y=0.1 to y=0.9, consistent with a radius of 0.1 for a 5x5 grid. + y_coords = np.linspace(0.1, 0.9, num_rows) + + # Margin for x coordinates, consistent with y_coords margins. + margin = 0.1 + + idx = 0 + for r_idx, count in enumerate(row_counts): + y = y_coords[r_idx] + + # Simplified staggering logic. + # Odd rows are shifted to sit in the gaps of even rows. + if r_idx % 2 == 0: # Even rows (0, 2, 4) + # Place circles edge-to-edge within the margins + x_coords = np.linspace(margin, 1.0 - margin, count) + else: # Odd rows (1, 3) are staggered + # Create space at the ends to shift the circles. + # linspace over (count+2) points and skipping the first and last + # achieves a simple and effective stagger. + x_coords = np.linspace(margin, 1.0 - margin, count + 2)[1:-1] + + for x in x_coords: + if idx < n: + centers[idx] = [x, y] + idx += 1 + + # The placement logic naturally keeps centers within the square. + # No clipping is necessary, as radii calculation correctly handles boundaries. + + # Compute maximum valid radii for this configuration + radii = compute_max_radii(centers) + return centers, radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e53dcad947695a4690fc1342a144a1bf05884e59 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..7a0c3b62b73ae7028b2c976f452c2446be76c2c6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/edit.diff @@ -0,0 +1,199 @@ +--- a/original.py ++++ b/original.py +@@ -1,194 +1,195 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid (optimal for 25 circles), + deforms it by creating a void using a Gaussian repulsive force, + and then places the 26th circle into that new, larger void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an interstitial void center. + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. +- void_center = np.array([0.4, 0.4]) ++ # To break the grid symmetry and find a better packing, we use an asymmetric void center. ++ void_center = np.array([0.4, 0.2]) + + # 3. Deform the grid by "pushing" points away from the void center + # using a Gaussian repulsive model. This creates space for the 26th circle. + amplitude = 0.04 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # Ensure centers remain within the unit square after deformation. + deformed_centers = np.clip(deformed_centers, 0.0, 1.0) + + centers[:25] = deformed_centers + + # 4. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) + boundary_margin = 0.04 # How close circles can get to boundary before repulsion + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Compute maximum valid radii for this newly relaxed configuration + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/main.py new file mode 100644 index 0000000000000000000000000000000000000000..61d260240c99b1e04f0f57cbbfa6433ff01481d9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/main.py @@ -0,0 +1,195 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid (optimal for 25 circles), + deforms it by creating a void using a Gaussian repulsive force, + and then places the 26th circle into that new, larger void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an interstitial void center. + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + # To break the grid symmetry and find a better packing, we use an asymmetric void center. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the grid by "pushing" points away from the void center + # using a Gaussian repulsive model. This creates space for the 26th circle. + amplitude = 0.04 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # Ensure centers remain within the unit square after deformation. + deformed_centers = np.clip(deformed_centers, 0.0, 1.0) + + centers[:25] = deformed_centers + + # 4. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) + boundary_margin = 0.04 # How close circles can get to boundary before repulsion + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Compute maximum valid radii for this newly relaxed configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/original.py new file mode 100644 index 0000000000000000000000000000000000000000..85fdb47c1d37aa6ddc0dfd79794fa46a5f9b6a7b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/original.py @@ -0,0 +1,194 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid (optimal for 25 circles), + deforms it by creating a void using a Gaussian repulsive force, + and then places the 26th circle into that new, larger void. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + grid_centers = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an interstitial void center. + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the grid by "pushing" points away from the void center + # using a Gaussian repulsive model. This creates space for the 26th circle. + amplitude = 0.04 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + # Calculate displacement vectors from the void center to each grid point + displacements = grid_centers - void_center + distances = np.linalg.norm(displacements, axis=1) + + # Avoid division by zero for any point at the void center + mask = distances > 1e-9 + + # Calculate push magnitude based on Gaussian function + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + displacements[mask] /= distances[mask, np.newaxis] + deformed_centers = grid_centers + displacements * push_magnitudes[:, np.newaxis] + + # Ensure centers remain within the unit square after deformation. + deformed_centers = np.clip(deformed_centers, 0.0, 1.0) + + centers[:25] = deformed_centers + + # 4. Place the 26th circle in the center of the created void. + centers[25] = void_center + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This improves upon simple iterative refinement by using different + # force parameters for exploration (global adjustment) and refinement (fine-tuning). + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing by being slightly less than 0.2 (grid spacing) + boundary_margin = 0.04 # How close circles can get to boundary before repulsion + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size + refinement_repulsion_strength = 0.005 # Weaker repulsion + refinement_boundary_strength = 0.025 # Weaker boundary repulsion + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Compute maximum valid radii for this newly relaxed configuration + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + radii = np.ones(n) + + # First, limit by distance to square borders + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..58985b681f7e4f43b1ac8fb4dfb11a11d31b51e8 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_71/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_71/results +Run 1/1 completed in 0.34 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9767542693444868 + public: {'centers_str': ' centers[0] = (0.0959, 0.0986)\n centers[1] = (0.2815, 0.0815)\n centers[2] = (0.5185, 0.0815)\n centers[3] = (0.7041, 0.0986)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0959, 0.3014)\n centers[6] = (0.2815, 0.3185)\n centers[7] = (0.5185, 0.3185)\n centers[8] = (0.7041, 0.3014)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0995, 0.5005)\n centers[11] = (0.2986, 0.5041)\n centers[12] = (0.5014, 0.5041)\n centers[13] = (0.7005, 0.5005)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7001)\n centers[17] = (0.5000, 0.7001)\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.4000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9767542693444868} + visualization_path: + execution_time_mean: 0.3367920438759029 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..2fb0a496b7a17faeec903271fde2ea86618f921e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9767542693444868, + "public": { + "centers_str": " centers[0] = (0.0959, 0.0986)\n centers[1] = (0.2815, 0.0815)\n centers[2] = (0.5185, 0.0815)\n centers[3] = (0.7041, 0.0986)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0959, 0.3014)\n centers[6] = (0.2815, 0.3185)\n centers[7] = (0.5185, 0.3185)\n centers[8] = (0.7041, 0.3014)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0995, 0.5005)\n centers[11] = (0.2986, 0.5041)\n centers[12] = (0.5014, 0.5041)\n centers[13] = (0.7005, 0.5005)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7001)\n centers[17] = (0.5000, 0.7001)\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.4000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9767542693444868 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_71/results/packing_viz.png", + "execution_time_mean": 0.3367920438759029, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..5c1c953032e05cc2c46424e39bba7e7400be82a9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_71/search_replace.txt @@ -0,0 +1,20 @@ + +asymmetric_void_initialization + + + +Based on the visualization, the current circle packing is trapped in a highly symmetric, grid-like local optimum. This is evident from the concentric rings of circles with vastly different sizes, particularly the large central circle surrounded by four very small, compressed circles. This structure leaves significant unused space between the inner and outer groups of circles, indicating an inefficient packing. + +To break this symmetry and allow the configuration to explore a more optimal, non-grid-like arrangement, I am changing the initial position of the 26th circle. Instead of placing it at the symmetric center of a grid void `(0.4, 0.4)`, I will place it at an asymmetric interstitial position `(0.4, 0.2)`. This also shifts the center of the initial Gaussian deformation, creating an unbalanced initial pressure that will force the circles to rearrange more dynamically during the subsequent force-directed relaxation stages. This should lead to a much denser and more effective overall packing. + + + +<<<<<<< SEARCH + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + void_center = np.array([0.4, 0.4]) +======= + # A central void in the 5x5 grid is at (0.4, 0.4). We will expand this void. + # To break the grid symmetry and find a better packing, we use an asymmetric void center. + void_center = np.array([0.4, 0.2]) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7c59c5762dabf24f7936546698622d8a814310a1 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..128d1da674d0938bd275039d9328e755bd4444aa --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/edit.diff @@ -0,0 +1,224 @@ +--- a/original.py ++++ b/original.py +@@ -1,179 +1,216 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by combining a + Gaussian-deformed grid initialization with a two-stage adaptive + force-directed relaxation to optimize the final positions. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a central void and deform the grid. + # We use a Gaussian push to create initial space. Parameters are from + # the successful inspiration program. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 # Displacement magnitude + sigma = 0.15 # Range of the repulsive force + + # Using a vectorized approach for displacement calculation + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + +- # 3. Two-Stage Adaptive Force-Directed Relaxation (Crossover from other prior programs) +- # This step is crucial. It takes the rough initial placement and lets the circles +- # settle into a much more efficient, relaxed packing. +- +- # Shared parameters for both stages: ++ # 3. Multi-Stage Adaptive Force-Directed Relaxation. ++ # This process takes the rough initial placement and lets the circles ++ # settle into a much more efficient, relaxed packing using sequential ++ # stages of decreasing force and step size. ++ ++ # Shared parameters for all stages: + repulsion_threshold = 0.185 # Encourages tight packing + boundary_margin = 0.04 # Distance from boundary to start repulsion + + # Stage 1: Exploration - Broad adjustments ++ # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning ++ # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ # Stage 3: Ultra-Low-Energy Annealing - Final Polish ++ # Applies very gentle forces over many iterations to push circles into ++ # their absolute tightest configuration, aiming to resolve any remaining ++ # micro-overlaps or sub-optimal gaps. ++ annealing_iters = 250 # More iterations for delicate adjustments ++ annealing_step_size = 0.0002 # Extremely small step size ++ annealing_repulsion_strength = 0.001 # Very weak repulsion ++ annealing_boundary_strength = 0.005 # Very weak boundary repulsion ++ ++ for _ in range(annealing_iters): ++ forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = annealing_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 4. Compute maximum valid radii for the final, relaxed configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/main.py new file mode 100644 index 0000000000000000000000000000000000000000..b09043d7b3b5c36d1acd2af36273bcf365f83846 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/main.py @@ -0,0 +1,216 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by combining a + Gaussian-deformed grid initialization with a two-stage adaptive + force-directed relaxation to optimize the final positions. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a central void and deform the grid. + # We use a Gaussian push to create initial space. Parameters are from + # the successful inspiration program. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 # Displacement magnitude + sigma = 0.15 # Range of the repulsive force + + # Using a vectorized approach for displacement calculation + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 3. Multi-Stage Adaptive Force-Directed Relaxation. + # This process takes the rough initial placement and lets the circles + # settle into a much more efficient, relaxed packing using sequential + # stages of decreasing force and step size. + + # Shared parameters for all stages: + repulsion_threshold = 0.185 # Encourages tight packing + boundary_margin = 0.04 # Distance from boundary to start repulsion + + # Stage 1: Exploration - Broad adjustments + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Ultra-Low-Energy Annealing - Final Polish + # Applies very gentle forces over many iterations to push circles into + # their absolute tightest configuration, aiming to resolve any remaining + # micro-overlaps or sub-optimal gaps. + annealing_iters = 250 # More iterations for delicate adjustments + annealing_step_size = 0.0002 # Extremely small step size + annealing_repulsion_strength = 0.001 # Very weak repulsion + annealing_boundary_strength = 0.005 # Very weak boundary repulsion + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 4. Compute maximum valid radii for the final, relaxed configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/original.py new file mode 100644 index 0000000000000000000000000000000000000000..6088f6edd2a6769b6efc4c2915fddcf2720df5c2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/original.py @@ -0,0 +1,179 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by combining a + Gaussian-deformed grid initialization with a two-stage adaptive + force-directed relaxation to optimize the final positions. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Initial Grid for 25 circles: Start with a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Place the 26th circle in a central void and deform the grid. + # We use a Gaussian push to create initial space. Parameters are from + # the successful inspiration program. + void_center = np.array([0.4, 0.4]) + amplitude = 0.042 # Displacement magnitude + sigma = 0.15 # Range of the repulsive force + + # Using a vectorized approach for displacement calculation + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 3. Two-Stage Adaptive Force-Directed Relaxation (Crossover from other prior programs) + # This step is crucial. It takes the rough initial placement and lets the circles + # settle into a much more efficient, relaxed packing. + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing + boundary_margin = 0.04 # Distance from boundary to start repulsion + + # Stage 1: Exploration - Broad adjustments + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 4. Compute maximum valid radii for the final, relaxed configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for a more accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # First, limit by distance to square borders (vectorized for efficiency) + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively limit by distance to other circles, allowing constraints to propagate + for _ in range(300): # Iterate to ensure convergence + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If current radii cause overlap + if radii[i] + radii[j] > dist: + sum_r = radii[i] + radii[j] + if sum_r > 1e-9: # Avoid division by zero for coincident centers + # Scale both radii proportionally to resolve overlap + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change to set the flag + if ri_new < radii[i] - 1e-9 or rj_new < radii[j] - 1e-9: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + if not changes_made: + break # Exit early if the configuration is stable + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..90cf6bbef43cc4e338c8827c1bf2d4cee1a0c5bc --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_72/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_72/results +Run 1/1 completed in 0.64 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9635686859451775 + public: {'centers_str': ' centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9635686859451775} + visualization_path: + execution_time_mean: 0.6400341638363898 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..fa068a5511120d6c459f6ad97a57351dd409f9b9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9635686859451775, + "public": { + "centers_str": " centers[0] = (0.0995, 0.0995)\n centers[1] = (0.2986, 0.0957)\n centers[2] = (0.5014, 0.0957)\n centers[3] = (0.7005, 0.0995)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0957, 0.2986)\n centers[6] = (0.2807, 0.2807)\n centers[7] = (0.5193, 0.2807)\n centers[8] = (0.7043, 0.2986)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0957, 0.5014)\n centers[11] = (0.2807, 0.5193)\n centers[12] = (0.5193, 0.5193)\n centers[13] = (0.7043, 0.5014)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0995, 0.7005)\n centers[16] = (0.2986, 0.7043)\n centers[17] = (0.5014, 0.7043)\n centers[18] = (0.7005, 0.7005)\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.4000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9635686859451775 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_72/results/packing_viz.png", + "execution_time_mean": 0.6400341638363898, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed3b3014ca69b5f1b7e6be2095ad5fa4ba32db5b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/rewrite.txt @@ -0,0 +1,192 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void, adopted from the inspiration program. + # This is the key to breaking the symmetric local optimum. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + boundary_margin = 0.04 + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Adopted from the inspiration program for more aggressive initial restructuring. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # A new stage from the inspiration program for final micro-adjustments. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 # Tighter threshold for final packing. + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..bfa8b30be952f7175dadd6f8fa00c37a95221764 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_72/search_replace.txt @@ -0,0 +1,191 @@ + +Add an "Ultra-Low-Energy Annealing" stage as a third and final relaxation step. This stage uses a larger number of iterations, but significantly smaller step sizes and repulsion strengths. The goal is to allow for extremely fine adjustments, helping circles settle into a denser, more stable local minimum by overcoming tiny energy barriers, without drastically altering the overall structure established in previous stages. This helps equalize circle sizes and fill small gaps more efficiently, as indicated by the visual where some smaller circles seem 'trapped' by larger ones. + + +<<<<<<< SEARCH + # 3. Two-Stage Adaptive Force-Directed Relaxation (Crossover from other prior programs) + # This step is crucial. It takes the rough initial placement and lets the circles + # settle into a much more efficient, relaxed packing. + + # Shared parameters for both stages: + repulsion_threshold = 0.185 # Encourages tight packing + boundary_margin = 0.04 # Distance from boundary to start repulsion + + # Stage 1: Exploration - Broad adjustments + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 4. Compute maximum valid radii for the final, relaxed configuration. + radii = compute_max_radii(centers) + return centers, radii +======= + # 3. Multi-Stage Adaptive Force-Directed Relaxation. + # This process takes the rough initial placement and lets the circles + # settle into a much more efficient, relaxed packing using sequential + # stages of decreasing force and step size. + + # Shared parameters for all stages: + repulsion_threshold = 0.185 # Encourages tight packing + boundary_margin = 0.04 # Distance from boundary to start repulsion + + # Stage 1: Exploration - Broad adjustments + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_boundary_strength = 0.025 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Ultra-Low-Energy Annealing - Final Polish + # Applies very gentle forces over many iterations to push circles into + # their absolute tightest configuration, aiming to resolve any remaining + # micro-overlaps or sub-optimal gaps. + annealing_iters = 250 # More iterations for delicate adjustments + annealing_step_size = 0.0002 # Extremely small step size + annealing_repulsion_strength = 0.001 # Very weak repulsion + annealing_boundary_strength = 0.005 # Very weak boundary repulsion + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 4. Compute maximum valid radii for the final, relaxed configuration. + radii = compute_max_radii(centers) + return centers, radii +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d4042d13e90277260d0eee9cdb4b145761a568c1 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..40e4d132489d90d4e45493ba87ba3238b5d2f7f3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/edit.diff @@ -0,0 +1,212 @@ +--- a/original.py ++++ b/original.py +@@ -1,202 +1,197 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. +- # Instead of (0.4, 0.4), using (0.4, 0.2) breaks the initial symmetry, +- # allowing the relaxation to find a less ordered and denser packing. ++ # Using (0.4, 0.2) breaks initial symmetry, encouraging unique, denser packings. + void_center = np.array([0.4, 0.2]) + +- # 3. Deform the 25 grid points with a Gaussian push from the void center. ++ # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + ++ # Common boundary margin for all stages + boundary_margin = 0.04 + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # A new stage for final micro-adjustments with very weak forces and many iterations. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 +- annealing_repulsion_threshold = 0.18 # Even tighter threshold for final packing ++ annealing_repulsion_threshold = 0.18 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + +- # Initialize radii based on distance to the square's boundaries. +- radii = np.zeros(n) +- for i in range(n): +- x, y = centers[i] +- radii[i] = min(x, 1 - x, y, 1 - y) ++ # Initialize radii based on distance to the square's boundaries using vectorized operation. ++ radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. +- # A high number of iterations ensures convergence for complex arrangements. ++ # A high number of iterations and tight tolerance ensures convergence. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii +- +- + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/main.py new file mode 100644 index 0000000000000000000000000000000000000000..a16a82f01c9eeb1a84b900120f31e7495853bb74 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/main.py @@ -0,0 +1,197 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Using (0.4, 0.2) breaks initial symmetry, encouraging unique, denser packings. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # Common boundary margin for all stages + boundary_margin = 0.04 + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # A new stage for final micro-adjustments with very weak forces and many iterations. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries using vectorized operation. + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations and tight tolerance ensures convergence. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/original.py new file mode 100644 index 0000000000000000000000000000000000000000..d9e17356508bbf96099a9b6c90090e5f4ff96760 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/original.py @@ -0,0 +1,202 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Instead of (0.4, 0.4), using (0.4, 0.2) breaks the initial symmetry, + # allowing the relaxation to find a less ordered and denser packing. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + boundary_margin = 0.04 + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # A new stage for final micro-adjustments with very weak forces and many iterations. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 # Even tighter threshold for final packing + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..dadd1c1d554aba69e01b36da205d1960c6f130f9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_73/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_73/results +Run 1/1 completed in 1.72 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9808569554223658 + 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} + private: {'reported_sum_of_radii': 1.9808569554223658} + visualization_path: + execution_time_mean: 1.7249507810920477 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..418c4374d81db4164cc921a707b212aa3a5649c9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9808569554223658, + "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 + }, + "private": { + "reported_sum_of_radii": 1.9808569554223658 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_73/results/packing_viz.png", + "execution_time_mean": 1.7249507810920477, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..773bbc5d4ffd57fd9db2b39ef70d9ddcb68e4fc2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_73/rewrite.txt @@ -0,0 +1,188 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Using (0.4, 0.2) breaks initial symmetry, encouraging unique, denser packings. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # Common boundary margin for all stages + boundary_margin = 0.04 + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # A new stage for final micro-adjustments with very weak forces and many iterations. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries using vectorized operation. + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations and tight tolerance ensures convergence. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1dd9e62ba412165e237e53a786d22a02d3ab6ca1 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..79ccf8a54cefe39a7da6cea75599d259eaf305e4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_74/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_74/results +Run 1/1 completed in 0.55 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9767569681884283 + public: {'centers_str': ' centers[0] = (0.0959, 0.0986)\n centers[1] = (0.2815, 0.0815)\n centers[2] = (0.5185, 0.0815)\n centers[3] = (0.7041, 0.0986)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0959, 0.3014)\n centers[6] = (0.2815, 0.3185)\n centers[7] = (0.5185, 0.3185)\n centers[8] = (0.7041, 0.3014)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0995, 0.5005)\n centers[11] = (0.2986, 0.5041)\n centers[12] = (0.5014, 0.5041)\n centers[13] = (0.7005, 0.5005)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7001)\n centers[17] = (0.5000, 0.7001)\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.4000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9767569681884283} + visualization_path: + execution_time_mean: 0.5470689390785992 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..0167cd2dff1520267d05331896e20f3dce999071 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9767569681884283, + "public": { + "centers_str": " centers[0] = (0.0959, 0.0986)\n centers[1] = (0.2815, 0.0815)\n centers[2] = (0.5185, 0.0815)\n centers[3] = (0.7041, 0.0986)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0959, 0.3014)\n centers[6] = (0.2815, 0.3185)\n centers[7] = (0.5185, 0.3185)\n centers[8] = (0.7041, 0.3014)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0995, 0.5005)\n centers[11] = (0.2986, 0.5041)\n centers[12] = (0.5014, 0.5041)\n centers[13] = (0.7005, 0.5005)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7001)\n centers[17] = (0.5000, 0.7001)\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.4000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9767569681884283 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_74/results/packing_viz.png", + "execution_time_mean": 0.5470689390785992, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6544960da492f97ad1358a77f34c59c3b123a2e5 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..f0fe281c3edc2499409dd3de350cff8a17dfd50a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/edit.diff @@ -0,0 +1,235 @@ +--- a/original.py ++++ b/original.py +@@ -1,193 +1,224 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. +- # A central interstitial void at (0.4, 0.4) is a good candidate, +- # as identified in previous successful runs. +- void_center = np.array([0.4, 0.4]) ++ # An asymmetric interstitial void is chosen to break the initial grid ++ # symmetry, which has been shown to lead to denser packings. ++ # The value (0.4, 0.2) is inspired by a previous high-scoring solution. ++ void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room for the 26th. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the unit square. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This strategy has proven more effective than a single-stage approach, + # allowing for distinct exploration and fine-tuning phases. + + # Shared parameters for both stages, restored to previously effective values: + repulsion_threshold = 0.185 # Encourages tighter packing by having circles repel slightly before direct contact. + boundary_margin = 0.04 # Distance from boundary where repulsion starts, allowing circles closer to edges. + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size for precise adjustments. + refinement_repulsion_strength = 0.005 # Weaker repulsion for stability. + refinement_boundary_strength = 0.025 # Weaker boundary repulsion for finer positioning. + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + ++ # Stage 3: Annealing - Final "polishing" of the configuration. ++ # This stage applies extremely gentle forces over many iterations to allow ++ # circles to settle into tight local minima without major disruptions. ++ annealing_iters = 250 ++ annealing_step_size = 0.0002 ++ annealing_repulsion_strength = 0.001 ++ annealing_boundary_strength = 0.005 ++ ++ for _ in range(annealing_iters): ++ forces = np.zeros_like(centers) ++ ++ # Circle-circle repulsion ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < repulsion_threshold: ++ force_magnitude = annealing_repulsion_strength * (repulsion_threshold - dist) / dist ++ force_vec = force_magnitude * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ ++ # Boundary repulsion ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) ++ ++ centers += annealing_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + +- # Initialize radii based on distance to the square's boundaries. +- radii = np.zeros(n) +- for i in range(n): +- x, y = centers[i] +- radii[i] = min(x, 1 - x, y, 1 - y) ++ # Initialize radii based on distance to the square's boundaries (vectorized). ++ radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: # Added small tolerance for numerical stability + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero for nearly coincident centers + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/main.py new file mode 100644 index 0000000000000000000000000000000000000000..dd19e068dd79a9ea6fc89c78da9edfed49713dd0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/main.py @@ -0,0 +1,224 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # An asymmetric interstitial void is chosen to break the initial grid + # symmetry, which has been shown to lead to denser packings. + # The value (0.4, 0.2) is inspired by a previous high-scoring solution. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room for the 26th. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the unit square. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This strategy has proven more effective than a single-stage approach, + # allowing for distinct exploration and fine-tuning phases. + + # Shared parameters for both stages, restored to previously effective values: + repulsion_threshold = 0.185 # Encourages tighter packing by having circles repel slightly before direct contact. + boundary_margin = 0.04 # Distance from boundary where repulsion starts, allowing circles closer to edges. + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size for precise adjustments. + refinement_repulsion_strength = 0.005 # Weaker repulsion for stability. + refinement_boundary_strength = 0.025 # Weaker boundary repulsion for finer positioning. + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Annealing - Final "polishing" of the configuration. + # This stage applies extremely gentle forces over many iterations to allow + # circles to settle into tight local minima without major disruptions. + annealing_iters = 250 + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 + annealing_boundary_strength = 0.005 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: # Added small tolerance for numerical stability + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero for nearly coincident centers + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/original.py new file mode 100644 index 0000000000000000000000000000000000000000..7d139958dbcdf53b1857b526cd8c211a1b363941 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/original.py @@ -0,0 +1,193 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # A central interstitial void at (0.4, 0.4) is a good candidate, + # as identified in previous successful runs. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room for the 26th. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the unit square. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This strategy has proven more effective than a single-stage approach, + # allowing for distinct exploration and fine-tuning phases. + + # Shared parameters for both stages, restored to previously effective values: + repulsion_threshold = 0.185 # Encourages tighter packing by having circles repel slightly before direct contact. + boundary_margin = 0.04 # Distance from boundary where repulsion starts, allowing circles closer to edges. + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size for precise adjustments. + refinement_repulsion_strength = 0.005 # Weaker repulsion for stability. + refinement_boundary_strength = 0.025 # Weaker boundary repulsion for finer positioning. + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: # Added small tolerance for numerical stability + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero for nearly coincident centers + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..7ad3c9c74142011f6752d5f7ffa18b2331f7b9b4 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_75/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_75/results +Run 1/1 completed in 0.63 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9773778109127131 + public: {'centers_str': ' centers[0] = (0.0957, 0.0986)\n centers[1] = (0.2807, 0.0807)\n centers[2] = (0.5193, 0.0807)\n centers[3] = (0.7043, 0.0986)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0957, 0.3014)\n centers[6] = (0.2807, 0.3193)\n centers[7] = (0.5193, 0.3193)\n centers[8] = (0.7043, 0.3014)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0995, 0.5005)\n centers[11] = (0.2986, 0.5043)\n centers[12] = (0.5014, 0.5043)\n centers[13] = (0.7005, 0.5005)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7001)\n centers[17] = (0.5000, 0.7001)\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.4000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9773778109127131} + visualization_path: + execution_time_mean: 0.6322175818495452 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..5ea3d30fd71e1af989d41927716a815547f6fb2e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9773778109127131, + "public": { + "centers_str": " centers[0] = (0.0957, 0.0986)\n centers[1] = (0.2807, 0.0807)\n centers[2] = (0.5193, 0.0807)\n centers[3] = (0.7043, 0.0986)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0957, 0.3014)\n centers[6] = (0.2807, 0.3193)\n centers[7] = (0.5193, 0.3193)\n centers[8] = (0.7043, 0.3014)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0995, 0.5005)\n centers[11] = (0.2986, 0.5043)\n centers[12] = (0.5014, 0.5043)\n centers[13] = (0.7005, 0.5005)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7001)\n centers[17] = (0.5000, 0.7001)\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.4000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9773778109127131 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_75/results/packing_viz.png", + "execution_time_mean": 0.6322175818495452, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..d23776d70428c0f1516622767238a9a84065d6ec --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/rewrite.txt @@ -0,0 +1,189 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + from an asymmetric void and applying a three-stage (exploration/refinement/annealing) + force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Using (0.4, 0.2) breaks initial symmetry, encouraging unique, denser packings. + # This was a key factor in a previous higher-scoring generation. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void for better exploration. + amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # Common boundary margin for all stages + boundary_margin = 0.04 + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 # Higher threshold for broader rearrangement + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 # Tighter threshold for settling + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # A new stage for final micro-adjustments with very weak forces and many iterations. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 # Even tighter threshold for final packing + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries using vectorized operation. + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations and tight tolerance ensures convergence. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7e1cfa8242e8dd6a1253e9d5eaeb6e3eb94bf6f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_75/search_replace.txt @@ -0,0 +1,98 @@ +Based on my analysis of the visual representation and the performance of prior attempts, the current packing suffers from excessive symmetry, leading to an inefficient use of space in the central region. The arrangement is too grid-like. A previous successful configuration used an asymmetric void to break this symmetry. I will reintroduce this concept and combine it with a more refined optimization process. + +My plan consists of two main improvements: +1. **Asymmetric Void Initialization:** I will change the initial void center from the symmetric `(0.4, 0.4)` to the asymmetric `(0.4, 0.2)`. This proven strategy disrupts the grid's initial symmetry, preventing the formation of the inefficient 'cross' of small circles seen in the visualization and encouraging a denser, more amorphous packing. +2. **Add Final Annealing Stage:** I will add a third, "annealing" relaxation stage. This stage uses extremely gentle forces over many iterations to perform a final "polishing" of the configuration, allowing circles to settle into tight local minima without the risk of large, destabilizing movements. This will fine-tune the positions established by the asymmetric start and the first two relaxation stages. + +These changes work in tandem: the asymmetric void provides a better starting point, and the annealing stage meticulously optimizes it. + + +asymmetric_void + + +The current symmetric void at (0.4, 0.4) results in a grid-like, inefficient packing, visible as four small circles squeezed around the large central one. To break this costly symmetry, I am moving the void center to an asymmetric position at (0.4, 0.2). This approach is inspired by a previous high-scoring program and is designed to allow the circles to settle into a more complex and denser final configuration during relaxation. + + +<<<<<<< SEARCH + # A central interstitial void at (0.4, 0.4) is a good candidate, + # as identified in previous successful runs. + void_center = np.array([0.4, 0.4]) +======= + # An asymmetric interstitial void is chosen to break the initial grid + # symmetry, which has been shown to lead to denser packings. + # The value (0.4, 0.2) is inspired by a previous high-scoring solution. + void_center = np.array([0.4, 0.2]) +>>>>>>> REPLACE + + +add_annealing_stage + + +I am adding a third "annealing" relaxation stage after the refinement phase. This stage uses very weak forces and a small step size over a high number of iterations. The goal is to perform a final "polishing" of the circle arrangement, allowing the circles to gently settle into their tightest possible positions and maximizing space utilization without destabilizing the overall structure established by the asymmetric void and initial relaxation stages. + + +<<<<<<< SEARCH + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) +======= + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Annealing - Final "polishing" of the configuration. + # This stage applies extremely gentle forces over many iterations to allow + # circles to settle into tight local minima without major disruptions. + annealing_iters = 250 + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 + annealing_boundary_strength = 0.005 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) +>>>>>>> REPLACE + + +vectorize_radius_initialization + + +This is a minor code quality improvement. The initial calculation of radii based on boundary distances is currently done with a Python loop. I am replacing this with a more efficient and idiomatic vectorized NumPy operation. This change does not alter the logic but improves code clarity and performance slightly. + + +<<<<<<< SEARCH + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) +======= + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be85f6ffc68134885f6446b3156637b89289d32f Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..1a2ad4dd41c9a25a770fd7346174257ffd48a212 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_76/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_76/results +Run 1/1 completed in 1.79 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.965593789322965 + public: {'centers_str': ' centers[0] = (0.0955, 0.0945)\n centers[1] = (0.2779, 0.0685)\n centers[2] = (0.5320, 0.0711)\n centers[3] = (0.7122, 0.1007)\n centers[4] = (0.9046, 0.1037)\n centers[5] = (0.0941, 0.2969)\n centers[6] = (0.2760, 0.3228)\n centers[7] = (0.5321, 0.3279)\n centers[8] = (0.7113, 0.3055)\n centers[9] = (0.9033, 0.3047)\n centers[10] = (0.0991, 0.4956)\n centers[11] = (0.2982, 0.5026)\n centers[12] = (0.4966, 0.5071)\n centers[13] = (0.7006, 0.5059)\n centers[14] = (0.9001, 0.5052)\n centers[15] = (0.0976, 0.6954)\n centers[16] = (0.2963, 0.6971)\n centers[17] = (0.4949, 0.7008)\n centers[18] = (0.6963, 0.7038)\n centers[19] = (0.8976, 0.7047)\n centers[20] = (0.0963, 0.8963)\n centers[21] = (0.2953, 0.8976)\n centers[22] = (0.4948, 0.9000)\n centers[23] = (0.6953, 0.9024)\n centers[24] = (0.8963, 0.9037)\n centers[25] = (0.4050, 0.1984)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.965593789322965} + visualization_path: + execution_time_mean: 1.792883550748229 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..bf2445b79ad50fcadb84da285e1c83f8a94bef24 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.965593789322965, + "public": { + "centers_str": " centers[0] = (0.0955, 0.0945)\n centers[1] = (0.2779, 0.0685)\n centers[2] = (0.5320, 0.0711)\n centers[3] = (0.7122, 0.1007)\n centers[4] = (0.9046, 0.1037)\n centers[5] = (0.0941, 0.2969)\n centers[6] = (0.2760, 0.3228)\n centers[7] = (0.5321, 0.3279)\n centers[8] = (0.7113, 0.3055)\n centers[9] = (0.9033, 0.3047)\n centers[10] = (0.0991, 0.4956)\n centers[11] = (0.2982, 0.5026)\n centers[12] = (0.4966, 0.5071)\n centers[13] = (0.7006, 0.5059)\n centers[14] = (0.9001, 0.5052)\n centers[15] = (0.0976, 0.6954)\n centers[16] = (0.2963, 0.6971)\n centers[17] = (0.4949, 0.7008)\n centers[18] = (0.6963, 0.7038)\n centers[19] = (0.8976, 0.7047)\n centers[20] = (0.0963, 0.8963)\n centers[21] = (0.2953, 0.8976)\n centers[22] = (0.4948, 0.9000)\n centers[23] = (0.6953, 0.9024)\n centers[24] = (0.8963, 0.9037)\n centers[25] = (0.4050, 0.1984)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.965593789322965 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_76/results/packing_viz.png", + "execution_time_mean": 1.792883550748229, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..85ba5b9c2e8bb3f55e09b60150813dfec068e5fe Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..7036c455eadcb4cd9464c8182d0d6d577dcd67d5 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_80/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_80/results +Run 1/1 completed in 0.86 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9814492632243264 + public: {'centers_str': ' centers[0] = (0.0923, 0.0982)\n centers[1] = (0.2731, 0.0714)\n centers[2] = (0.5269, 0.0714)\n centers[3] = (0.7072, 0.0982)\n centers[4] = (0.9007, 0.1000)\n centers[5] = (0.0923, 0.3018)\n centers[6] = (0.2729, 0.3271)\n centers[7] = (0.5271, 0.3271)\n centers[8] = (0.7072, 0.3018)\n centers[9] = (0.9007, 0.3000)\n centers[10] = (0.0991, 0.5008)\n centers[11] = (0.2982, 0.5072)\n centers[12] = (0.5018, 0.5072)\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.7006)\n centers[17] = (0.5000, 0.7006)\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.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.4000, 0.1999)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9814492632243264} + visualization_path: + execution_time_mean: 0.8559018918313086 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..1c8f99ab238def78e64fd7dbe650ca43bf55a61d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9814492632243264, + "public": { + "centers_str": " centers[0] = (0.0923, 0.0982)\n centers[1] = (0.2731, 0.0714)\n centers[2] = (0.5269, 0.0714)\n centers[3] = (0.7072, 0.0982)\n centers[4] = (0.9007, 0.1000)\n centers[5] = (0.0923, 0.3018)\n centers[6] = (0.2729, 0.3271)\n centers[7] = (0.5271, 0.3271)\n centers[8] = (0.7072, 0.3018)\n centers[9] = (0.9007, 0.3000)\n centers[10] = (0.0991, 0.5008)\n centers[11] = (0.2982, 0.5072)\n centers[12] = (0.5018, 0.5072)\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.7006)\n centers[17] = (0.5000, 0.7006)\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.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.4000, 0.1999)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9814492632243264 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_80/results/packing_viz.png", + "execution_time_mean": 0.8559018918313086, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..694b07de34381cce88c6cf3bcc8977cf0b7176fc Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..042dc6cfad73670712bd3347227804aa46ef66d6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/edit.diff @@ -0,0 +1,258 @@ +--- a/original.py ++++ b/original.py +@@ -1,224 +1,229 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # An asymmetric interstitial void is chosen to break the initial grid + # symmetry, which has been shown to lead to denser packings. + # The value (0.4, 0.2) is inspired by a previous high-scoring solution. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room for the 26th. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push: +- amplitude = 0.042 # The maximum distance to push a circle. ++ amplitude = 0.04 # The maximum distance to push a circle. (Reverted from 0.042 for potentially better balance) + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the unit square. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This strategy has proven more effective than a single-stage approach, + # allowing for distinct exploration and fine-tuning phases. + +- # Shared parameters for both stages, restored to previously effective values: +- repulsion_threshold = 0.185 # Encourages tighter packing by having circles repel slightly before direct contact. +- boundary_margin = 0.04 # Distance from boundary where repulsion starts, allowing circles closer to edges. ++ # Stage-specific parameters will be defined within each stage, ++ # as different phases of relaxation benefit from different repulsion and boundary behaviors. + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 ++ exploration_repulsion_threshold = 0.19 # Slightly larger threshold for broader initial interaction ++ exploration_boundary_margin = 0.04 # Standard margin for exploration + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist ++ if 0 < dist < exploration_repulsion_threshold: ++ force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) ++ if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) ++ if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) ++ if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) ++ if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size for precise adjustments. + refinement_repulsion_strength = 0.005 # Weaker repulsion for stability. + refinement_boundary_strength = 0.025 # Weaker boundary repulsion for finer positioning. ++ refinement_repulsion_threshold = 0.18 # Tighter threshold for precise packing ++ refinement_boundary_margin = 0.02 # Smaller margin to allow circles closer to edges + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist ++ if 0 < dist < refinement_repulsion_threshold: # Use refinement-specific threshold ++ force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) ++ if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) ++ if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) ++ if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) ++ if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Annealing - Final "polishing" of the configuration. + # This stage applies extremely gentle forces over many iterations to allow + # circles to settle into tight local minima without major disruptions. +- annealing_iters = 250 +- annealing_step_size = 0.0002 +- annealing_repulsion_strength = 0.001 +- annealing_boundary_strength = 0.005 ++ annealing_iters = 300 # Increased iterations for more thorough annealing ++ annealing_step_size = 0.00015 # Even smaller step size for ultra-fine adjustments ++ annealing_repulsion_strength = 0.0008 # Even weaker repulsion for delicate balance ++ annealing_boundary_strength = 0.002 # Weaker boundary repulsion for precise edge packing ++ annealing_repulsion_threshold = 0.17 # Very tight threshold for final packing ++ annealing_boundary_margin = 0.005 # Extremely small margin to push circles to the absolute edge + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_magnitude = annealing_repulsion_strength * (repulsion_threshold - dist) / dist ++ if 0 < dist < annealing_repulsion_threshold: # Use annealing-specific threshold ++ force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] +- if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) +- if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) +- if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) +- if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) ++ if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) ++ if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) ++ if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) ++ if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: # Added small tolerance for numerical stability + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero for nearly coincident centers + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/main.py new file mode 100644 index 0000000000000000000000000000000000000000..9b7998375fbb55f04b840f373252293b01172a43 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/main.py @@ -0,0 +1,229 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # An asymmetric interstitial void is chosen to break the initial grid + # symmetry, which has been shown to lead to denser packings. + # The value (0.4, 0.2) is inspired by a previous high-scoring solution. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room for the 26th. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push: + amplitude = 0.04 # The maximum distance to push a circle. (Reverted from 0.042 for potentially better balance) + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the unit square. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This strategy has proven more effective than a single-stage approach, + # allowing for distinct exploration and fine-tuning phases. + + # Stage-specific parameters will be defined within each stage, + # as different phases of relaxation benefit from different repulsion and boundary behaviors. + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + exploration_repulsion_threshold = 0.19 # Slightly larger threshold for broader initial interaction + exploration_boundary_margin = 0.04 # Standard margin for exploration + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size for precise adjustments. + refinement_repulsion_strength = 0.005 # Weaker repulsion for stability. + refinement_boundary_strength = 0.025 # Weaker boundary repulsion for finer positioning. + refinement_repulsion_threshold = 0.18 # Tighter threshold for precise packing + refinement_boundary_margin = 0.02 # Smaller margin to allow circles closer to edges + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: # Use refinement-specific threshold + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Annealing - Final "polishing" of the configuration. + # This stage applies extremely gentle forces over many iterations to allow + # circles to settle into tight local minima without major disruptions. + annealing_iters = 300 # Increased iterations for more thorough annealing + annealing_step_size = 0.00015 # Even smaller step size for ultra-fine adjustments + annealing_repulsion_strength = 0.0008 # Even weaker repulsion for delicate balance + annealing_boundary_strength = 0.002 # Weaker boundary repulsion for precise edge packing + annealing_repulsion_threshold = 0.17 # Very tight threshold for final packing + annealing_boundary_margin = 0.005 # Extremely small margin to push circles to the absolute edge + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: # Use annealing-specific threshold + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: # Added small tolerance for numerical stability + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero for nearly coincident centers + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/original.py new file mode 100644 index 0000000000000000000000000000000000000000..dd19e068dd79a9ea6fc89c78da9edfed49713dd0 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/original.py @@ -0,0 +1,224 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # An asymmetric interstitial void is chosen to break the initial grid + # symmetry, which has been shown to lead to denser packings. + # The value (0.4, 0.2) is inspired by a previous high-scoring solution. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room for the 26th. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the unit square. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This strategy has proven more effective than a single-stage approach, + # allowing for distinct exploration and fine-tuning phases. + + # Shared parameters for both stages, restored to previously effective values: + repulsion_threshold = 0.185 # Encourages tighter packing by having circles repel slightly before direct contact. + boundary_margin = 0.04 # Distance from boundary where repulsion starts, allowing circles closer to edges. + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size for precise adjustments. + refinement_repulsion_strength = 0.005 # Weaker repulsion for stability. + refinement_boundary_strength = 0.025 # Weaker boundary repulsion for finer positioning. + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Annealing - Final "polishing" of the configuration. + # This stage applies extremely gentle forces over many iterations to allow + # circles to settle into tight local minima without major disruptions. + annealing_iters = 250 + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 + annealing_boundary_strength = 0.005 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: # Added small tolerance for numerical stability + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero for nearly coincident centers + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..b5b2b2484ddcb501b5601bf971308a1ec5fcf8ba --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_82/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_82/results +Run 1/1 completed in 0.74 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9767274896549336 + public: {'centers_str': ' centers[0] = (0.0958, 0.0986)\n centers[1] = (0.2815, 0.0815)\n centers[2] = (0.5185, 0.0815)\n centers[3] = (0.7042, 0.0986)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0958, 0.3014)\n centers[6] = (0.2815, 0.3185)\n centers[7] = (0.5185, 0.3185)\n centers[8] = (0.7042, 0.3014)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0995, 0.5005)\n centers[11] = (0.2986, 0.5042)\n centers[12] = (0.5014, 0.5042)\n centers[13] = (0.7005, 0.5005)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7001)\n centers[17] = (0.5000, 0.7001)\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.4000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9767274896549336} + visualization_path: + execution_time_mean: 0.7363607757724822 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..8ad802c9d4ad8ee5af0a2620901f4b2996a33fe6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9767274896549336, + "public": { + "centers_str": " centers[0] = (0.0958, 0.0986)\n centers[1] = (0.2815, 0.0815)\n centers[2] = (0.5185, 0.0815)\n centers[3] = (0.7042, 0.0986)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0958, 0.3014)\n centers[6] = (0.2815, 0.3185)\n centers[7] = (0.5185, 0.3185)\n centers[8] = (0.7042, 0.3014)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0995, 0.5005)\n centers[11] = (0.2986, 0.5042)\n centers[12] = (0.5014, 0.5042)\n centers[13] = (0.7005, 0.5005)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7001)\n centers[17] = (0.5000, 0.7001)\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.4000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9767274896549336 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_82/results/packing_viz.png", + "execution_time_mean": 0.7363607757724822, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..9ebc5b7ae286fe3f84d86709df39300dd64b2947 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_82/search_replace.txt @@ -0,0 +1,226 @@ +revert_gaussian_amplitude +Reverts the Gaussian push amplitude to 0.04, which was present in a prior program achieving a sum of radii of 1.98. This aims to create a less aggressive initial displacement, potentially leading to a more balanced distribution of circle sizes compared to the current 0.042. + +<<<<<<< SEARCH + # Tuned hyperparameters for the Gaussian push: + amplitude = 0.042 # The maximum distance to push a circle. + sigma = 0.15 # The "spread" of the push, controlling its influence range. +======= + # Tuned hyperparameters for the Gaussian push: + amplitude = 0.04 # The maximum distance to push a circle. (Reverted from 0.042 for potentially better balance) + sigma = 0.15 # The "spread" of the push, controlling its influence range. +>>>>>>> REPLACE + + +stage_specific_force_params +Introduces stage-specific repulsion thresholds and boundary margins for each relaxation stage. This allows for broader interaction and boundary distance during exploration, and progressively tighter packing and closer proximity to boundaries during refinement and annealing. This directly addresses recommendations 2 and 5 (granular hyperparameter control). The global `repulsion_threshold` and `boundary_margin` are removed, and specific parameters are defined for `exploration`, `refinement`, and `annealing` stages. The annealing parameters are also further fine-tuned for an even gentler polish as per recommendation 1. + +<<<<<<< SEARCH + # Shared parameters for both stages, restored to previously effective values: + repulsion_threshold = 0.185 # Encourages tighter packing by having circles repel slightly before direct contact. + boundary_margin = 0.04 # Distance from boundary where repulsion starts, allowing circles closer to edges. + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size for precise adjustments. + refinement_repulsion_strength = 0.005 # Weaker repulsion for stability. + refinement_boundary_strength = 0.025 # Weaker boundary repulsion for finer positioning. + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Annealing - Final "polishing" of the configuration. + # This stage applies extremely gentle forces over many iterations to allow + # circles to settle into tight local minima without major disruptions. + annealing_iters = 250 + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 + annealing_boundary_strength = 0.005 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) +======= + # Stage-specific parameters will be defined within each stage, + # as different phases of relaxation benefit from different repulsion and boundary behaviors. + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + exploration_repulsion_threshold = 0.19 # Slightly larger threshold for broader initial interaction + exploration_boundary_margin = 0.04 # Standard margin for exploration + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size for precise adjustments. + refinement_repulsion_strength = 0.005 # Weaker repulsion for stability. + refinement_boundary_strength = 0.025 # Weaker boundary repulsion for finer positioning. + refinement_repulsion_threshold = 0.18 # Tighter threshold for precise packing + refinement_boundary_margin = 0.02 # Smaller margin to allow circles closer to edges + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: # Use refinement-specific threshold + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Annealing - Final "polishing" of the configuration. + # This stage applies extremely gentle forces over many iterations to allow + # circles to settle into tight local minima without major disruptions. + annealing_iters = 300 # Increased iterations for more thorough annealing + annealing_step_size = 0.00015 # Even smaller step size for ultra-fine adjustments + annealing_repulsion_strength = 0.0008 # Even weaker repulsion for delicate balance + annealing_boundary_strength = 0.002 # Weaker boundary repulsion for precise edge packing + annealing_repulsion_threshold = 0.17 # Very tight threshold for final packing + annealing_boundary_margin = 0.005 # Extremely small margin to push circles to the absolute edge + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: # Use annealing-specific threshold + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2dfd9d46eb0e9e7d04df00cf4e71ff7d8fbcaeec Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..f260b2eb7f380647153a92e59c23ddca861a2f95 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_84/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_84/results +Run 1/1 completed in 0.66 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.976728361209187 + public: {'centers_str': ' centers[0] = (0.0958, 0.0986)\n centers[1] = (0.2815, 0.0815)\n centers[2] = (0.5185, 0.0815)\n centers[3] = (0.7042, 0.0986)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0958, 0.3014)\n centers[6] = (0.2815, 0.3185)\n centers[7] = (0.5185, 0.3185)\n centers[8] = (0.7042, 0.3014)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0995, 0.5005)\n centers[11] = (0.2986, 0.5042)\n centers[12] = (0.5014, 0.5042)\n centers[13] = (0.7005, 0.5005)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7001)\n centers[17] = (0.5000, 0.7001)\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.4000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.976728361209187} + visualization_path: + execution_time_mean: 0.6550491936504841 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..d552d6a9ebb5d95921024aa7171952d5ff164508 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.976728361209187, + "public": { + "centers_str": " centers[0] = (0.0958, 0.0986)\n centers[1] = (0.2815, 0.0815)\n centers[2] = (0.5185, 0.0815)\n centers[3] = (0.7042, 0.0986)\n centers[4] = (0.9001, 0.1000)\n centers[5] = (0.0958, 0.3014)\n centers[6] = (0.2815, 0.3185)\n centers[7] = (0.5185, 0.3185)\n centers[8] = (0.7042, 0.3014)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0995, 0.5005)\n centers[11] = (0.2986, 0.5042)\n centers[12] = (0.5014, 0.5042)\n centers[13] = (0.7005, 0.5005)\n centers[14] = (0.9000, 0.5000)\n centers[15] = (0.1000, 0.7000)\n centers[16] = (0.3000, 0.7001)\n centers[17] = (0.5000, 0.7001)\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.4000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.976728361209187 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_84/results/packing_viz.png", + "execution_time_mean": 0.6550491936504841, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3dafe52dccdedfae55e2c393b12019a87d29b224 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..ad51519621393d407ea5323ed94b050a7ef0e85d --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_86/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_86/results +Run 1/1 completed in 1.81 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9778615315939718 + public: {'centers_str': ' centers[0] = (0.0926, 0.0965)\n centers[1] = (0.2731, 0.0679)\n centers[2] = (0.5302, 0.0689)\n centers[3] = (0.7098, 0.0990)\n centers[4] = (0.9025, 0.1015)\n centers[5] = (0.0918, 0.3002)\n centers[6] = (0.2717, 0.3280)\n centers[7] = (0.5296, 0.3290)\n centers[8] = (0.7091, 0.3026)\n centers[9] = (0.9018, 0.3016)\n centers[10] = (0.0991, 0.4993)\n centers[11] = (0.2982, 0.5075)\n centers[12] = (0.5017, 0.5083)\n centers[13] = (0.7009, 0.5017)\n centers[14] = (0.9001, 0.5016)\n centers[15] = (0.0992, 0.6985)\n centers[16] = (0.2992, 0.7001)\n centers[17] = (0.4992, 0.7009)\n centers[18] = (0.6992, 0.7009)\n centers[19] = (0.8992, 0.7016)\n centers[20] = (0.0984, 0.8984)\n centers[21] = (0.2984, 0.8993)\n centers[22] = (0.4984, 0.9001)\n centers[23] = (0.6984, 0.9008)\n centers[24] = (0.8984, 0.9016)\n centers[25] = (0.4012, 0.1995)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9778615315939718} + visualization_path: + execution_time_mean: 1.8085863050073385 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..af43844cfc7a09317e719ec2672d7bf142492a54 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9778615315939718, + "public": { + "centers_str": " centers[0] = (0.0926, 0.0965)\n centers[1] = (0.2731, 0.0679)\n centers[2] = (0.5302, 0.0689)\n centers[3] = (0.7098, 0.0990)\n centers[4] = (0.9025, 0.1015)\n centers[5] = (0.0918, 0.3002)\n centers[6] = (0.2717, 0.3280)\n centers[7] = (0.5296, 0.3290)\n centers[8] = (0.7091, 0.3026)\n centers[9] = (0.9018, 0.3016)\n centers[10] = (0.0991, 0.4993)\n centers[11] = (0.2982, 0.5075)\n centers[12] = (0.5017, 0.5083)\n centers[13] = (0.7009, 0.5017)\n centers[14] = (0.9001, 0.5016)\n centers[15] = (0.0992, 0.6985)\n centers[16] = (0.2992, 0.7001)\n centers[17] = (0.4992, 0.7009)\n centers[18] = (0.6992, 0.7009)\n centers[19] = (0.8992, 0.7016)\n centers[20] = (0.0984, 0.8984)\n centers[21] = (0.2984, 0.8993)\n centers[22] = (0.4984, 0.9001)\n centers[23] = (0.6984, 0.9008)\n centers[24] = (0.8984, 0.9016)\n centers[25] = (0.4012, 0.1995)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9778615315939718 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_86/results/packing_viz.png", + "execution_time_mean": 1.8085863050073385, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..743c9143f4de3a4c19944765839bd57a2323ece9 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..2d3224721c1aa89378c495916175f4979c99f41a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/edit.diff @@ -0,0 +1,212 @@ +--- a/original.py ++++ b/original.py +@@ -1,205 +1,205 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid, deforms it by creating an asymmetric void + using a Gaussian repulsive force, and then uses a three-stage force-directed + relaxation (Exploration, Refinement, Annealing) to settle the circles into + a dense packing. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an asymmetric interstitial void center to break symmetry. +- # This position is taken from the best-performing parent program. +- void_center = np.array([0.4, 0.2]) ++ # This position is adjusted to balance circle sizes more effectively. ++ void_center = np.array([0.35, 0.35]) + + # 3. Deform the grid using a vectorized Gaussian push. +- # The amplitude is slightly increased, inspired by other successful programs. +- amplitude = 0.042 # Magnitude of the push. ++ # The amplitude is slightly reduced to prevent overly small surrounding circles. ++ amplitude = 0.038 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th and clip to bounds. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Three-Stage Adaptive Force-Directed Relaxation. + # This crossover introduces the third "Annealing" stage for final polishing. + + # 4. Three-Stage Adaptive Force-Directed Relaxation. + # This crossover introduces the third "Annealing" stage for final polishing. + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_repulsion_threshold = 0.20 # Increased for broader interaction + exploration_boundary_strength = 0.075 + exploration_boundary_margin = 0.06 # Larger margin for more exploration freedom + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_repulsion_threshold = 0.19 # Tighter threshold for closer packing + refinement_boundary_strength = 0.025 + refinement_boundary_margin = 0.02 # Smaller margin for tighter boundary fit + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Annealing - Final "polishing" of the configuration (Crossover element). + annealing_iters = 250 + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 + annealing_repulsion_threshold = 0.18 # Even tighter for final touches + annealing_boundary_strength = 0.005 + annealing_boundary_margin = 0.005 # Minimal margin for ultimate boundary contact + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change before updating + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/main.py new file mode 100644 index 0000000000000000000000000000000000000000..386eafe01258dd6aa5137b79ca2b0cd8c1038249 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/main.py @@ -0,0 +1,205 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid, deforms it by creating an asymmetric void + using a Gaussian repulsive force, and then uses a three-stage force-directed + relaxation (Exploration, Refinement, Annealing) to settle the circles into + a dense packing. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an asymmetric interstitial void center to break symmetry. + # This position is adjusted to balance circle sizes more effectively. + void_center = np.array([0.35, 0.35]) + + # 3. Deform the grid using a vectorized Gaussian push. + # The amplitude is slightly reduced to prevent overly small surrounding circles. + amplitude = 0.038 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th and clip to bounds. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Three-Stage Adaptive Force-Directed Relaxation. + # This crossover introduces the third "Annealing" stage for final polishing. + + # 4. Three-Stage Adaptive Force-Directed Relaxation. + # This crossover introduces the third "Annealing" stage for final polishing. + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_repulsion_threshold = 0.20 # Increased for broader interaction + exploration_boundary_strength = 0.075 + exploration_boundary_margin = 0.06 # Larger margin for more exploration freedom + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_repulsion_threshold = 0.19 # Tighter threshold for closer packing + refinement_boundary_strength = 0.025 + refinement_boundary_margin = 0.02 # Smaller margin for tighter boundary fit + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Annealing - Final "polishing" of the configuration (Crossover element). + annealing_iters = 250 + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 + annealing_repulsion_threshold = 0.18 # Even tighter for final touches + annealing_boundary_strength = 0.005 + annealing_boundary_margin = 0.005 # Minimal margin for ultimate boundary contact + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change before updating + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/original.py new file mode 100644 index 0000000000000000000000000000000000000000..17300295f0e4dd88317ea5a5256d479be3d995e3 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/original.py @@ -0,0 +1,205 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + This method starts with a 5x5 grid, deforms it by creating an asymmetric void + using a Gaussian repulsive force, and then uses a three-stage force-directed + relaxation (Exploration, Refinement, Annealing) to settle the circles into + a dense packing. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid, the basis for N=25 packing. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an asymmetric interstitial void center to break symmetry. + # This position is taken from the best-performing parent program. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the grid using a vectorized Gaussian push. + # The amplitude is slightly increased, inspired by other successful programs. + amplitude = 0.042 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + # Normalize displacement vectors and apply the push + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # Combine deformed 25 circles with the 26th and clip to bounds. + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Three-Stage Adaptive Force-Directed Relaxation. + # This crossover introduces the third "Annealing" stage for final polishing. + + # 4. Three-Stage Adaptive Force-Directed Relaxation. + # This crossover introduces the third "Annealing" stage for final polishing. + + # Stage 1: Exploration - Broad adjustment and global distribution + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_repulsion_threshold = 0.20 # Increased for broader interaction + exploration_boundary_strength = 0.075 + exploration_boundary_margin = 0.06 # Larger margin for more exploration freedom + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + refinement_iters = 150 + refinement_step_size = 0.0008 + refinement_repulsion_strength = 0.005 + refinement_repulsion_threshold = 0.19 # Tighter threshold for closer packing + refinement_boundary_strength = 0.025 + refinement_boundary_margin = 0.02 # Smaller margin for tighter boundary fit + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Annealing - Final "polishing" of the configuration (Crossover element). + annealing_iters = 250 + annealing_step_size = 0.0002 + annealing_repulsion_strength = 0.001 + annealing_repulsion_threshold = 0.18 # Even tighter for final touches + annealing_boundary_strength = 0.005 + annealing_boundary_margin = 0.005 # Minimal margin for ultimate boundary contact + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Compute maximum valid radii for the final configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + # Check for significant change before updating + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..9ee94cebbc66ec957a6e2dc7a55edd236706326e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_87/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_87/results +Run 1/1 completed in 0.66 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9109335807086734 + public: {'centers_str': ' centers[0] = (0.0983, 0.0983)\n centers[1] = (0.2983, 0.0909)\n centers[2] = (0.5029, 0.0950)\n centers[3] = (0.7005, 0.0996)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0909, 0.2983)\n centers[6] = (0.2736, 0.2736)\n centers[7] = (0.5207, 0.2930)\n centers[8] = (0.7027, 0.2997)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0950, 0.5029)\n centers[11] = (0.2930, 0.5207)\n centers[12] = (0.5097, 0.5097)\n centers[13] = (0.7015, 0.5006)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0996, 0.7005)\n centers[16] = (0.2997, 0.7027)\n centers[17] = (0.5006, 0.7015)\n centers[18] = (0.7001, 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.3523, 0.3523)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9109335807086734} + visualization_path: + execution_time_mean: 0.6579713700339198 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..1735cc923aadafc50cbab79f6087b813f9e8a29f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9109335807086734, + "public": { + "centers_str": " centers[0] = (0.0983, 0.0983)\n centers[1] = (0.2983, 0.0909)\n centers[2] = (0.5029, 0.0950)\n centers[3] = (0.7005, 0.0996)\n centers[4] = (0.9000, 0.1000)\n centers[5] = (0.0909, 0.2983)\n centers[6] = (0.2736, 0.2736)\n centers[7] = (0.5207, 0.2930)\n centers[8] = (0.7027, 0.2997)\n centers[9] = (0.9001, 0.3000)\n centers[10] = (0.0950, 0.5029)\n centers[11] = (0.2930, 0.5207)\n centers[12] = (0.5097, 0.5097)\n centers[13] = (0.7015, 0.5006)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.0996, 0.7005)\n centers[16] = (0.2997, 0.7027)\n centers[17] = (0.5006, 0.7015)\n centers[18] = (0.7001, 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.3523, 0.3523)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9109335807086734 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_87/results/packing_viz.png", + "execution_time_mean": 0.6579713700339198, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..403e03c9426ea919de572c6ac46723fdcdb05f1c --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_87/search_replace.txt @@ -0,0 +1,31 @@ +change_void_and_amplitude + +rebalance_void_push + + + +The visualization clearly shows a very large circle at `(0.4, 0.2)` (the `void_center`) surrounded by several significantly smaller circles. This "dominant" circle likely comes at the expense of its neighbors, reducing the overall sum of radii. To improve the packing efficiency and create a more balanced distribution of circle sizes, I am proposing two changes: + +1. **Shift `void_center`**: Moving the `void_center` from `(0.4, 0.2)` to `(0.35, 0.35)` makes it less extreme on the y-axis and slightly shifts it to the left. This aims to allow circles in the `(0.5, 0.2)` and `(0.7, 0.2)` regions to potentially grow larger, contributing more to the total sum, while still maintaining an asymmetric void. +2. **Reduce Gaussian `amplitude`**: Decreasing the `amplitude` of the Gaussian push from `0.042` to `0.038` will lessen the repulsive force applied to the initial 25 grid circles. This should prevent the surrounding circles from becoming excessively small due to the void creation, leading to a more uniform distribution of radii and a higher overall sum. + + + +<<<<<<< SEARCH + # This position is taken from the best-performing parent program. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the grid using a vectorized Gaussian push. + # The amplitude is slightly increased, inspired by other successful programs. + amplitude = 0.042 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. +======= + # This position is adjusted to balance circle sizes more effectively. + void_center = np.array([0.35, 0.35]) + + # 3. Deform the grid using a vectorized Gaussian push. + # The amplitude is slightly reduced to prevent overly small surrounding circles. + amplitude = 0.038 # Magnitude of the push. + sigma = 0.15 # Spatial extent of the push. +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db3bca1b3935da4887074cd2be8a15746dfe975e Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..1519a070c2789c111e24407027f859f427d6c671 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/edit.diff @@ -0,0 +1,373 @@ +--- a/original.py ++++ b/original.py +@@ -1,229 +1,187 @@ + # EVOLVE-BLOCK-START +-"""Constructor-based circle packing for n=26 circles""" ++""" ++Constructor-based circle packing for n=26 circles using a vectorized class-based ++approach designed to aggressively break the initial grid symmetry. ++""" + + import numpy as np ++ ++class CirclePacker: ++ """ ++ A vectorized class for packing circles, optimized for performance and tuned ++ to break out of grid-like local optima. ++ """ ++ ++ def __init__(self, n=26): ++ """Initializes the packer with the number of circles.""" ++ self.n = n ++ self.centers = np.zeros((n, 2)) ++ ++ def _initialize_grid_with_void(self, void_center, amplitude, sigma): ++ """ ++ Creates an initial configuration by aggressively deforming a 5x5 grid. ++ A strong Gaussian push creates a chaotic starting state to avoid the ++ suboptimal grid-like minima seen in previous results. ++ """ ++ # 1. Start with the 25 centers of a 5x5 grid. ++ x_coords = np.linspace(0.1, 0.9, 5) ++ y_coords = np.linspace(0.1, 0.9, 5) ++ xx, yy = np.meshgrid(x_coords, y_coords) ++ base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T ++ ++ # 2. Deform the grid with a strong Gaussian push. ++ displacements = base_centers_25 - void_center ++ distances = np.linalg.norm(displacements, axis=1) ++ mask = distances > 1e-9 ++ ++ push_magnitudes = np.zeros(25) ++ if np.any(mask): ++ push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) ++ displacements[mask] /= distances[mask, np.newaxis] # Normalize ++ ++ deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] ++ ++ # 3. Place the circles and clip. ++ self.centers[:25] = deformed_centers_25 ++ self.centers[25] = void_center ++ self.centers = np.clip(self.centers, 0.0, 1.0) ++ ++ ++ def _relax_stage_vectorized(self, iters, step_size, repulsion_strength, ++ boundary_strength, repulsion_threshold, boundary_margin): ++ """ ++ Performs a force-directed relaxation stage using vectorized calculations ++ for high efficiency, enabling more iterations. ++ """ ++ for _ in range(iters): ++ # 1. Vectorized Circle-Circle Repulsion ++ diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] ++ dists = np.linalg.norm(diff, axis=2) ++ ++ # Create a mask for pairs of circles that are close enough to repel ++ mask = (dists > 1e-9) & (dists < repulsion_threshold) ++ ++ # Calculate scalar force magnitudes ++ force_scalar = np.zeros_like(dists) ++ force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] ++ ++ # Convert to force vectors and sum forces on each circle ++ force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ forces = np.sum(force_vectors, axis=1) ++ ++ # 2. Vectorized Boundary Repulsion ++ forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) ++ forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) ++ forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) ++ forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) ++ ++ # 3. Apply forces and clip ++ self.centers += step_size * forces ++ self.centers = np.clip(self.centers, 0.0, 1.0) ++ ++ ++ def pack(self): ++ """ ++ Orchestrates the entire packing process, from aggressive initialization ++ to multi-stage relaxation. ++ """ ++ # --- Initialization Stage --- ++ # Increased amplitude to shatter the initial grid structure. ++ self._initialize_grid_with_void( ++ void_center=np.array([0.4, 0.2]), ++ amplitude=0.08, # Increased from 0.04 to create more initial chaos ++ sigma=0.15 ++ ) ++ ++ # --- Relaxation Stage 1: Grid Breaking --- ++ # Increased threshold and strength to force circles out of grid alignment. ++ self._relax_stage_vectorized( ++ iters=200, # More iterations to handle the chaotic start ++ step_size=0.0025, ++ repulsion_strength=0.03, # Stronger push ++ boundary_strength=0.075, ++ repulsion_threshold=0.22, # > 0.2 grid spacing to break structure ++ boundary_margin=0.04 ++ ) ++ ++ # --- Relaxation Stage 2: Refinement --- ++ # Settle the now-disordered system into a dense configuration. ++ self._relax_stage_vectorized( ++ iters=250, # More iterations for better settling ++ step_size=0.0008, ++ repulsion_strength=0.005, ++ boundary_strength=0.025, ++ repulsion_threshold=0.19, # Reduced but still active threshold ++ boundary_margin=0.02 ++ ) ++ ++ # --- Relaxation Stage 3: Annealing --- ++ # Final polish with many iterations and extremely gentle forces. ++ self._relax_stage_vectorized( ++ iters=400, # Many iterations for a fine polish ++ step_size=0.00015, ++ repulsion_strength=0.001, ++ boundary_strength=0.005, ++ repulsion_threshold=0.18, # Final tight threshold ++ boundary_margin=0.005 ++ ) ++ ++ return self.centers + + + def construct_packing(): + """ +- Construct a specific arrangement of 26 circles in a unit square +- that attempts to maximize the sum of their radii. +- +- Returns: +- Tuple of (centers, radii) +- centers: np.array of shape (26, 2) with (x, y) coordinates +- radii: np.array of shape (26) with radius of each circle ++ Constructs a high-density arrangement of 26 circles using the vectorized ++ CirclePacker class. + """ +- # Initialize arrays for 26 circles +- n = 26 +- centers = np.zeros((n, 2)) +- +- # 1. Start with the 25 centers of a 5x5 grid. +- x_coords = np.linspace(0.1, 0.9, 5) +- y_coords = np.linspace(0.1, 0.9, 5) +- xx, yy = np.meshgrid(x_coords, y_coords) +- base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T +- +- # 2. Define the center of the void where the 26th circle will be placed. +- # An asymmetric interstitial void is chosen to break the initial grid +- # symmetry, which has been shown to lead to denser packings. +- # The value (0.4, 0.2) is inspired by a previous high-scoring solution. +- void_center = np.array([0.4, 0.2]) +- +- # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. +- # This pushes nearby circles away to make more room for the 26th. +- deformed_centers_25 = np.copy(base_centers_25) +- +- # Tuned hyperparameters for the Gaussian push: +- amplitude = 0.04 # The maximum distance to push a circle. (Reverted from 0.042 for potentially better balance) +- sigma = 0.15 # The "spread" of the push, controlling its influence range. +- +- for i in range(25): +- pos_vector = base_centers_25[i] - void_center +- dist_sq = np.sum(pos_vector**2) +- +- # Gaussian function defines the push magnitude based on distance from the void center. +- push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) +- +- # The push is directed radially away from the void center. +- if np.linalg.norm(pos_vector) > 1e-9: +- direction = pos_vector / np.linalg.norm(pos_vector) +- displacement = direction * push_magnitude +- deformed_centers_25[i] += displacement +- +- # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. +- centers[:25] = deformed_centers_25 +- centers[25] = void_center +- +- # Clip centers to ensure they stay within the unit square. +- centers = np.clip(centers, 0.0, 1.0) +- +- # 5. Two-Stage Adaptive Force-Directed Relaxation. +- # This strategy has proven more effective than a single-stage approach, +- # allowing for distinct exploration and fine-tuning phases. +- +- # Stage-specific parameters will be defined within each stage, +- # as different phases of relaxation benefit from different repulsion and boundary behaviors. +- +- # Stage 1: Exploration - Broad adjustment and global distribution +- # Aims to rapidly resolve initial overlaps and broadly distribute circles. +- exploration_iters = 100 +- exploration_step_size = 0.0025 +- exploration_repulsion_strength = 0.015 +- exploration_boundary_strength = 0.075 +- exploration_repulsion_threshold = 0.19 # Slightly larger threshold for broader initial interaction +- exploration_boundary_margin = 0.04 # Standard margin for exploration +- +- for _ in range(exploration_iters): +- forces = np.zeros_like(centers) +- +- # Circle-circle repulsion +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < exploration_repulsion_threshold: +- force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist +- force_vec = force_magnitude * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- +- # Boundary repulsion +- for i in range(n): +- x, y = centers[i] +- if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) +- if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) +- if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) +- if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) +- +- centers += exploration_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- +- # Stage 2: Refinement - Fine-tuning and precise adjustments +- # Uses smaller movements to converge to a better local optimum. +- refinement_iters = 150 +- refinement_step_size = 0.0008 # Much smaller step size for precise adjustments. +- refinement_repulsion_strength = 0.005 # Weaker repulsion for stability. +- refinement_boundary_strength = 0.025 # Weaker boundary repulsion for finer positioning. +- refinement_repulsion_threshold = 0.18 # Tighter threshold for precise packing +- refinement_boundary_margin = 0.02 # Smaller margin to allow circles closer to edges +- +- for _ in range(refinement_iters): +- forces = np.zeros_like(centers) +- +- # Circle-circle repulsion +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < refinement_repulsion_threshold: # Use refinement-specific threshold +- force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist +- force_vec = force_magnitude * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- +- # Boundary repulsion +- for i in range(n): +- x, y = centers[i] +- if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) +- if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) +- if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) +- if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) +- +- centers += refinement_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- +- # Stage 3: Annealing - Final "polishing" of the configuration. +- # This stage applies extremely gentle forces over many iterations to allow +- # circles to settle into tight local minima without major disruptions. +- annealing_iters = 300 # Increased iterations for more thorough annealing +- annealing_step_size = 0.00015 # Even smaller step size for ultra-fine adjustments +- annealing_repulsion_strength = 0.0008 # Even weaker repulsion for delicate balance +- annealing_boundary_strength = 0.002 # Weaker boundary repulsion for precise edge packing +- annealing_repulsion_threshold = 0.17 # Very tight threshold for final packing +- annealing_boundary_margin = 0.005 # Extremely small margin to push circles to the absolute edge +- +- for _ in range(annealing_iters): +- forces = np.zeros_like(centers) +- +- # Circle-circle repulsion +- for i in range(n): +- for j in range(i + 1, n): +- vec = centers[i] - centers[j] +- dist = np.linalg.norm(vec) +- if 0 < dist < annealing_repulsion_threshold: # Use annealing-specific threshold +- force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist +- force_vec = force_magnitude * (vec / dist) +- forces[i] += force_vec +- forces[j] -= force_vec +- +- # Boundary repulsion +- for i in range(n): +- x, y = centers[i] +- if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) +- if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) +- if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) +- if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) +- +- centers += annealing_step_size * forces +- centers = np.clip(centers, 0.0, 1.0) +- +- # 6. Compute maximum valid radii for the final, refined configuration. ++ packer = CirclePacker(n=26) ++ centers = packer.pack() + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position +- such that they don't overlap and stay within the unit square. This is +- an iterative version that converges to a stable solution. +- +- Args: +- centers: np.array of shape (n, 2) with (x, y) coordinates +- +- Returns: +- np.array of shape (n) with radius of each circle ++ such that they don't overlap and stay within the unit square. This version ++ iteratively resolves conflicts until convergence for an accurate result. + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False +- # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) +- if radii[i] + radii[j] > dist + 1e-12: # Added small tolerance for numerical stability +- # Scale both radii down proportionally to resolve the overlap. ++ if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] +- if sum_r > 1e-12: # Avoid division by zero for nearly coincident centers ++ if sum_r > 1e-12: + scale = dist / sum_r +- radii[i] *= scale +- radii[j] *= scale +- else: # If both radii are already ~0, ensure they are exactly 0 +- radii[i] = 0 +- radii[j] = 0 ++ ri_new = radii[i] * scale ++ rj_new = radii[j] * scale ++ ++ if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: ++ radii[i] = ri_new ++ radii[j] = rj_new ++ changes_made = True + +- changes_made = True +- +- # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/main.py new file mode 100644 index 0000000000000000000000000000000000000000..b30a6894d0abd6ee7c1c62d6481604a713b00ce8 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/main.py @@ -0,0 +1,187 @@ +# EVOLVE-BLOCK-START +""" +Constructor-based circle packing for n=26 circles using a vectorized class-based +approach designed to aggressively break the initial grid symmetry. +""" + +import numpy as np + +class CirclePacker: + """ + A vectorized class for packing circles, optimized for performance and tuned + to break out of grid-like local optima. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initialize_grid_with_void(self, void_center, amplitude, sigma): + """ + Creates an initial configuration by aggressively deforming a 5x5 grid. + A strong Gaussian push creates a chaotic starting state to avoid the + suboptimal grid-like minima seen in previous results. + """ + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a strong Gaussian push. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] # Normalize + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the circles and clip. + self.centers[:25] = deformed_centers_25 + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _relax_stage_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Performs a force-directed relaxation stage using vectorized calculations + for high efficiency, enabling more iterations. + """ + for _ in range(iters): + # 1. Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Create a mask for pairs of circles that are close enough to repel + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + # Calculate scalar force magnitudes + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Convert to force vectors and sum forces on each circle + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # 2. Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + # 3. Apply forces and clip + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def pack(self): + """ + Orchestrates the entire packing process, from aggressive initialization + to multi-stage relaxation. + """ + # --- Initialization Stage --- + # Increased amplitude to shatter the initial grid structure. + self._initialize_grid_with_void( + void_center=np.array([0.4, 0.2]), + amplitude=0.08, # Increased from 0.04 to create more initial chaos + sigma=0.15 + ) + + # --- Relaxation Stage 1: Grid Breaking --- + # Increased threshold and strength to force circles out of grid alignment. + self._relax_stage_vectorized( + iters=200, # More iterations to handle the chaotic start + step_size=0.0025, + repulsion_strength=0.03, # Stronger push + boundary_strength=0.075, + repulsion_threshold=0.22, # > 0.2 grid spacing to break structure + boundary_margin=0.04 + ) + + # --- Relaxation Stage 2: Refinement --- + # Settle the now-disordered system into a dense configuration. + self._relax_stage_vectorized( + iters=250, # More iterations for better settling + step_size=0.0008, + repulsion_strength=0.005, + boundary_strength=0.025, + repulsion_threshold=0.19, # Reduced but still active threshold + boundary_margin=0.02 + ) + + # --- Relaxation Stage 3: Annealing --- + # Final polish with many iterations and extremely gentle forces. + self._relax_stage_vectorized( + iters=400, # Many iterations for a fine polish + step_size=0.00015, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, # Final tight threshold + boundary_margin=0.005 + ) + + return self.centers + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the vectorized + CirclePacker class. + """ + packer = CirclePacker(n=26) + centers = packer.pack() + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/original.py new file mode 100644 index 0000000000000000000000000000000000000000..9b7998375fbb55f04b840f373252293b01172a43 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/original.py @@ -0,0 +1,229 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Construct a specific arrangement of 26 circles in a unit square + that attempts to maximize the sum of their radii. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + # Initialize arrays for 26 circles + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + # An asymmetric interstitial void is chosen to break the initial grid + # symmetry, which has been shown to lead to denser packings. + # The value (0.4, 0.2) is inspired by a previous high-scoring solution. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + # This pushes nearby circles away to make more room for the 26th. + deformed_centers_25 = np.copy(base_centers_25) + + # Tuned hyperparameters for the Gaussian push: + amplitude = 0.04 # The maximum distance to push a circle. (Reverted from 0.042 for potentially better balance) + sigma = 0.15 # The "spread" of the push, controlling its influence range. + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + + # Gaussian function defines the push magnitude based on distance from the void center. + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + + # The push is directed radially away from the void center. + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + # 4. Place the deformed 25 circles and add the 26th in the now-enlarged void. + centers[:25] = deformed_centers_25 + centers[25] = void_center + + # Clip centers to ensure they stay within the unit square. + centers = np.clip(centers, 0.0, 1.0) + + # 5. Two-Stage Adaptive Force-Directed Relaxation. + # This strategy has proven more effective than a single-stage approach, + # allowing for distinct exploration and fine-tuning phases. + + # Stage-specific parameters will be defined within each stage, + # as different phases of relaxation benefit from different repulsion and boundary behaviors. + + # Stage 1: Exploration - Broad adjustment and global distribution + # Aims to rapidly resolve initial overlaps and broadly distribute circles. + exploration_iters = 100 + exploration_step_size = 0.0025 + exploration_repulsion_strength = 0.015 + exploration_boundary_strength = 0.075 + exploration_repulsion_threshold = 0.19 # Slightly larger threshold for broader initial interaction + exploration_boundary_margin = 0.04 # Standard margin for exploration + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_magnitude = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 2: Refinement - Fine-tuning and precise adjustments + # Uses smaller movements to converge to a better local optimum. + refinement_iters = 150 + refinement_step_size = 0.0008 # Much smaller step size for precise adjustments. + refinement_repulsion_strength = 0.005 # Weaker repulsion for stability. + refinement_boundary_strength = 0.025 # Weaker boundary repulsion for finer positioning. + refinement_repulsion_threshold = 0.18 # Tighter threshold for precise packing + refinement_boundary_margin = 0.02 # Smaller margin to allow circles closer to edges + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: # Use refinement-specific threshold + force_magnitude = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # Stage 3: Annealing - Final "polishing" of the configuration. + # This stage applies extremely gentle forces over many iterations to allow + # circles to settle into tight local minima without major disruptions. + annealing_iters = 300 # Increased iterations for more thorough annealing + annealing_step_size = 0.00015 # Even smaller step size for ultra-fine adjustments + annealing_repulsion_strength = 0.0008 # Even weaker repulsion for delicate balance + annealing_boundary_strength = 0.002 # Weaker boundary repulsion for precise edge packing + annealing_repulsion_threshold = 0.17 # Very tight threshold for final packing + annealing_boundary_margin = 0.005 # Extremely small margin to push circles to the absolute edge + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + + # Circle-circle repulsion + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: # Use annealing-specific threshold + force_magnitude = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_magnitude * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + + # Boundary repulsion + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the final, refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: # Added small tolerance for numerical stability + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero for nearly coincident centers + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changes_made = True + + # If a full pass resulted in no changes, the packing is stable. + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..421c378d04514f6c48d4a8fbecb8427de3b7270e --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_89/main.py:69: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..8d7117e00c41d39266070684e577b97e3cb17efa --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_89/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_89/results +Run 1/1 completed in 0.14 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9762554634049385 + public: {'centers_str': ' centers[0] = (0.0883, 0.0969)\n centers[1] = (0.2658, 0.0615)\n centers[2] = (0.5341, 0.0615)\n centers[3] = (0.7097, 0.0969)\n centers[4] = (0.9024, 0.0985)\n centers[5] = (0.0881, 0.3016)\n centers[6] = (0.2650, 0.3348)\n centers[7] = (0.5349, 0.3349)\n centers[8] = (0.7098, 0.3016)\n centers[9] = (0.9024, 0.3000)\n centers[10] = (0.0975, 0.5010)\n centers[11] = (0.2983, 0.5098)\n centers[12] = (0.5016, 0.5098)\n centers[13] = (0.7010, 0.5010)\n centers[14] = (0.9016, 0.5000)\n centers[15] = (0.0985, 0.7002)\n centers[16] = (0.2999, 0.7010)\n centers[17] = (0.5000, 0.7010)\n centers[18] = (0.7001, 0.7002)\n centers[19] = (0.9014, 0.7001)\n centers[20] = (0.0986, 0.9014)\n centers[21] = (0.2999, 0.9015)\n centers[22] = (0.5000, 0.9015)\n centers[23] = (0.7001, 0.9014)\n centers[24] = (0.9014, 0.9014)\n centers[25] = (0.4000, 0.1999)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9762554634049385} + visualization_path: + execution_time_mean: 0.13936688285320997 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..f783f7f502c8e6a5c38f7e89c6ef04cb109c1603 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9762554634049385, + "public": { + "centers_str": " centers[0] = (0.0883, 0.0969)\n centers[1] = (0.2658, 0.0615)\n centers[2] = (0.5341, 0.0615)\n centers[3] = (0.7097, 0.0969)\n centers[4] = (0.9024, 0.0985)\n centers[5] = (0.0881, 0.3016)\n centers[6] = (0.2650, 0.3348)\n centers[7] = (0.5349, 0.3349)\n centers[8] = (0.7098, 0.3016)\n centers[9] = (0.9024, 0.3000)\n centers[10] = (0.0975, 0.5010)\n centers[11] = (0.2983, 0.5098)\n centers[12] = (0.5016, 0.5098)\n centers[13] = (0.7010, 0.5010)\n centers[14] = (0.9016, 0.5000)\n centers[15] = (0.0985, 0.7002)\n centers[16] = (0.2999, 0.7010)\n centers[17] = (0.5000, 0.7010)\n centers[18] = (0.7001, 0.7002)\n centers[19] = (0.9014, 0.7001)\n centers[20] = (0.0986, 0.9014)\n centers[21] = (0.2999, 0.9015)\n centers[22] = (0.5000, 0.9015)\n centers[23] = (0.7001, 0.9014)\n centers[24] = (0.9014, 0.9014)\n centers[25] = (0.4000, 0.1999)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9762554634049385 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_89/results/packing_viz.png", + "execution_time_mean": 0.13936688285320997, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/rewrite.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/rewrite.txt new file mode 100644 index 0000000000000000000000000000000000000000..6771cae82b4aad48fc287ece06c4a345ae71a7a9 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_89/rewrite.txt @@ -0,0 +1,178 @@ +# EVOLVE-BLOCK-START +""" +Constructor-based circle packing for n=26 circles using a vectorized class-based +approach designed to aggressively break the initial grid symmetry. +""" + +import numpy as np + +class CirclePacker: + """ + A vectorized class for packing circles, optimized for performance and tuned + to break out of grid-like local optima. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initialize_grid_with_void(self, void_center, amplitude, sigma): + """ + Creates an initial configuration by aggressively deforming a 5x5 grid. + A strong Gaussian push creates a chaotic starting state to avoid the + suboptimal grid-like minima seen in previous results. + """ + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a strong Gaussian push. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] # Normalize + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the circles and clip. + self.centers[:25] = deformed_centers_25 + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _relax_stage_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Performs a force-directed relaxation stage using vectorized calculations + for high efficiency, enabling more iterations. + """ + for _ in range(iters): + # 1. Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Create a mask for pairs of circles that are close enough to repel + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + # Calculate scalar force magnitudes + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Convert to force vectors and sum forces on each circle + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # 2. Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + # 3. Apply forces and clip + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def pack(self): + """ + Orchestrates the entire packing process, from aggressive initialization + to multi-stage relaxation. + """ + # --- Initialization Stage --- + # Increased amplitude to shatter the initial grid structure. + self._initialize_grid_with_void( + void_center=np.array([0.4, 0.2]), + amplitude=0.08, # Increased from 0.04 to create more initial chaos + sigma=0.15 + ) + + # --- Relaxation Stage 1: Grid Breaking --- + # Increased threshold and strength to force circles out of grid alignment. + self._relax_stage_vectorized( + iters=200, # More iterations to handle the chaotic start + step_size=0.0025, + repulsion_strength=0.03, # Stronger push + boundary_strength=0.075, + repulsion_threshold=0.22, # > 0.2 grid spacing to break structure + boundary_margin=0.04 + ) + + # --- Relaxation Stage 2: Refinement --- + # Settle the now-disordered system into a dense configuration. + self._relax_stage_vectorized( + iters=250, # More iterations for better settling + step_size=0.0008, + repulsion_strength=0.005, + boundary_strength=0.025, + repulsion_threshold=0.19, # Reduced but still active threshold + boundary_margin=0.02 + ) + + # --- Relaxation Stage 3: Annealing --- + # Final polish with many iterations and extremely gentle forces. + self._relax_stage_vectorized( + iters=400, # Many iterations for a fine polish + step_size=0.00015, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, # Final tight threshold + boundary_margin=0.005 + ) + + return self.centers + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the vectorized + CirclePacker class. + """ + packer = CirclePacker(n=26) + centers = packer.pack() + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9212505c047e0cfddc4b0fa03a6a5402f300dc7e Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..a77fde8a664d0309390cdcc0513d02939da671f8 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/edit.diff @@ -0,0 +1,224 @@ +--- a/original.py ++++ b/original.py +@@ -1,187 +1,203 @@ + # EVOLVE-BLOCK-START + """ + Constructor-based circle packing for n=26 circles using a vectorized class-based + approach designed to aggressively break the initial grid symmetry. + """ + + import numpy as np + + class CirclePacker: + """ + A vectorized class for packing circles, optimized for performance and tuned + to break out of grid-like local optima. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initialize_grid_with_void(self, void_center, amplitude, sigma): + """ + Creates an initial configuration by aggressively deforming a 5x5 grid. + A strong Gaussian push creates a chaotic starting state to avoid the + suboptimal grid-like minima seen in previous results. + """ + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a strong Gaussian push. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] # Normalize + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the circles and clip. + self.centers[:25] = deformed_centers_25 + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _relax_stage_vectorized(self, iters, step_size, repulsion_strength, +- boundary_strength, repulsion_threshold, boundary_margin): ++ boundary_strength, repulsion_threshold, boundary_margin, tangential_strength=0.0): + """ + Performs a force-directed relaxation stage using vectorized calculations +- for high efficiency, enabling more iterations. ++ for high efficiency. Can include a tangential 'vortex' force to break symmetries. + """ + for _ in range(iters): +- # 1. Vectorized Circle-Circle Repulsion ++ # 1. Vectorized Circle-Circle Interaction + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + +- # Create a mask for pairs of circles that are close enough to repel ++ # Mask for pairs of circles that are close enough to interact + mask = (dists > 1e-9) & (dists < repulsion_threshold) + +- # Calculate scalar force magnitudes ++ # Normalized difference vector, handling division by zero ++ normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) ++ ++ # --- Radial Repulsion Force --- + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] +- +- # Convert to force vectors and sum forces on each circle +- force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) +- forces = np.sum(force_vectors, axis=1) ++ radial_force_vectors = force_scalar[:, :, np.newaxis] * normalized_diff ++ ++ forces = np.sum(radial_force_vectors, axis=1) ++ ++ # --- Tangential Vortex Force (Optional) --- ++ if tangential_strength > 0: ++ # Tangential direction is 90-degree rotation of radial direction ++ tangential_dir = np.stack([-normalized_diff[:, :, 1], normalized_diff[:, :, 0]], axis=-1) ++ ++ # Use same falloff, but with tangential strength ++ tangential_scalar = np.zeros_like(dists) ++ tangential_scalar[mask] = tangential_strength * (repulsion_threshold - dists[mask]) / dists[mask] ++ ++ tangential_force_vectors = tangential_scalar[:, :, np.newaxis] * tangential_dir ++ forces += np.sum(tangential_force_vectors, axis=1) + + # 2. Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + # 3. Apply forces and clip + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def pack(self): + """ + Orchestrates the entire packing process, from aggressive initialization +- to multi-stage relaxation. ++ to multi-stage relaxation including a vortex stage. + """ + # --- Initialization Stage --- + # Increased amplitude to shatter the initial grid structure. + self._initialize_grid_with_void( + void_center=np.array([0.4, 0.2]), + amplitude=0.08, # Increased from 0.04 to create more initial chaos + sigma=0.15 + ) + +- # --- Relaxation Stage 1: Grid Breaking --- +- # Increased threshold and strength to force circles out of grid alignment. ++ # --- Relaxation Stage 1: Vortex Stir --- ++ # A new stage that applies tangential forces to "stir" the circles, ++ # breaking the grid symmetry more effectively than pure repulsion. + self._relax_stage_vectorized( +- iters=200, # More iterations to handle the chaotic start +- step_size=0.0025, +- repulsion_strength=0.03, # Stronger push +- boundary_strength=0.075, +- repulsion_threshold=0.22, # > 0.2 grid spacing to break structure +- boundary_margin=0.04 ++ iters=100, ++ step_size=0.002, ++ repulsion_strength=0.02, ++ boundary_strength=0.05, ++ repulsion_threshold=0.20, ++ boundary_margin=0.04, ++ tangential_strength=0.015 # Induces a swirl + ) + + # --- Relaxation Stage 2: Refinement --- + # Settle the now-disordered system into a dense configuration. + self._relax_stage_vectorized( + iters=250, # More iterations for better settling + step_size=0.0008, + repulsion_strength=0.005, + boundary_strength=0.025, + repulsion_threshold=0.19, # Reduced but still active threshold + boundary_margin=0.02 + ) + + # --- Relaxation Stage 3: Annealing --- + # Final polish with many iterations and extremely gentle forces. + self._relax_stage_vectorized( + iters=400, # Many iterations for a fine polish + step_size=0.00015, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, # Final tight threshold + boundary_margin=0.005 + ) + + return self.centers + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the vectorized + CirclePacker class. + """ + packer = CirclePacker(n=26) + centers = packer.pack() + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + if not changes_made: + break + + return radii + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/main.py new file mode 100644 index 0000000000000000000000000000000000000000..00ca1dce880091838cb77b50c5b6ccdf17d57093 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/main.py @@ -0,0 +1,203 @@ +# EVOLVE-BLOCK-START +""" +Constructor-based circle packing for n=26 circles using a vectorized class-based +approach designed to aggressively break the initial grid symmetry. +""" + +import numpy as np + +class CirclePacker: + """ + A vectorized class for packing circles, optimized for performance and tuned + to break out of grid-like local optima. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initialize_grid_with_void(self, void_center, amplitude, sigma): + """ + Creates an initial configuration by aggressively deforming a 5x5 grid. + A strong Gaussian push creates a chaotic starting state to avoid the + suboptimal grid-like minima seen in previous results. + """ + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a strong Gaussian push. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] # Normalize + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the circles and clip. + self.centers[:25] = deformed_centers_25 + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _relax_stage_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin, tangential_strength=0.0): + """ + Performs a force-directed relaxation stage using vectorized calculations + for high efficiency. Can include a tangential 'vortex' force to break symmetries. + """ + for _ in range(iters): + # 1. Vectorized Circle-Circle Interaction + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Mask for pairs of circles that are close enough to interact + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + # Normalized difference vector, handling division by zero + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # --- Radial Repulsion Force --- + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + radial_force_vectors = force_scalar[:, :, np.newaxis] * normalized_diff + + forces = np.sum(radial_force_vectors, axis=1) + + # --- Tangential Vortex Force (Optional) --- + if tangential_strength > 0: + # Tangential direction is 90-degree rotation of radial direction + tangential_dir = np.stack([-normalized_diff[:, :, 1], normalized_diff[:, :, 0]], axis=-1) + + # Use same falloff, but with tangential strength + tangential_scalar = np.zeros_like(dists) + tangential_scalar[mask] = tangential_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + tangential_force_vectors = tangential_scalar[:, :, np.newaxis] * tangential_dir + forces += np.sum(tangential_force_vectors, axis=1) + + # 2. Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + # 3. Apply forces and clip + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def pack(self): + """ + Orchestrates the entire packing process, from aggressive initialization + to multi-stage relaxation including a vortex stage. + """ + # --- Initialization Stage --- + # Increased amplitude to shatter the initial grid structure. + self._initialize_grid_with_void( + void_center=np.array([0.4, 0.2]), + amplitude=0.08, # Increased from 0.04 to create more initial chaos + sigma=0.15 + ) + + # --- Relaxation Stage 1: Vortex Stir --- + # A new stage that applies tangential forces to "stir" the circles, + # breaking the grid symmetry more effectively than pure repulsion. + self._relax_stage_vectorized( + iters=100, + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.05, + repulsion_threshold=0.20, + boundary_margin=0.04, + tangential_strength=0.015 # Induces a swirl + ) + + # --- Relaxation Stage 2: Refinement --- + # Settle the now-disordered system into a dense configuration. + self._relax_stage_vectorized( + iters=250, # More iterations for better settling + step_size=0.0008, + repulsion_strength=0.005, + boundary_strength=0.025, + repulsion_threshold=0.19, # Reduced but still active threshold + boundary_margin=0.02 + ) + + # --- Relaxation Stage 3: Annealing --- + # Final polish with many iterations and extremely gentle forces. + self._relax_stage_vectorized( + iters=400, # Many iterations for a fine polish + step_size=0.00015, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, # Final tight threshold + boundary_margin=0.005 + ) + + return self.centers + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the vectorized + CirclePacker class. + """ + packer = CirclePacker(n=26) + centers = packer.pack() + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/original.py new file mode 100644 index 0000000000000000000000000000000000000000..886cbf70719f51e828af24f2b88004c148768a22 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/original.py @@ -0,0 +1,187 @@ +# EVOLVE-BLOCK-START +""" +Constructor-based circle packing for n=26 circles using a vectorized class-based +approach designed to aggressively break the initial grid symmetry. +""" + +import numpy as np + +class CirclePacker: + """ + A vectorized class for packing circles, optimized for performance and tuned + to break out of grid-like local optima. + """ + + def __init__(self, n=26): + """Initializes the packer with the number of circles.""" + self.n = n + self.centers = np.zeros((n, 2)) + + def _initialize_grid_with_void(self, void_center, amplitude, sigma): + """ + Creates an initial configuration by aggressively deforming a 5x5 grid. + A strong Gaussian push creates a chaotic starting state to avoid the + suboptimal grid-like minima seen in previous results. + """ + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Deform the grid with a strong Gaussian push. + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + if np.any(mask): + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + displacements[mask] /= distances[mask, np.newaxis] # Normalize + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + # 3. Place the circles and clip. + self.centers[:25] = deformed_centers_25 + self.centers[25] = void_center + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def _relax_stage_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Performs a force-directed relaxation stage using vectorized calculations + for high efficiency, enabling more iterations. + """ + for _ in range(iters): + # 1. Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Create a mask for pairs of circles that are close enough to repel + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + # Calculate scalar force magnitudes + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Convert to force vectors and sum forces on each circle + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # 2. Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + # 3. Apply forces and clip + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) + + + def pack(self): + """ + Orchestrates the entire packing process, from aggressive initialization + to multi-stage relaxation. + """ + # --- Initialization Stage --- + # Increased amplitude to shatter the initial grid structure. + self._initialize_grid_with_void( + void_center=np.array([0.4, 0.2]), + amplitude=0.08, # Increased from 0.04 to create more initial chaos + sigma=0.15 + ) + + # --- Relaxation Stage 1: Grid Breaking --- + # Increased threshold and strength to force circles out of grid alignment. + self._relax_stage_vectorized( + iters=200, # More iterations to handle the chaotic start + step_size=0.0025, + repulsion_strength=0.03, # Stronger push + boundary_strength=0.075, + repulsion_threshold=0.22, # > 0.2 grid spacing to break structure + boundary_margin=0.04 + ) + + # --- Relaxation Stage 2: Refinement --- + # Settle the now-disordered system into a dense configuration. + self._relax_stage_vectorized( + iters=250, # More iterations for better settling + step_size=0.0008, + repulsion_strength=0.005, + boundary_strength=0.025, + repulsion_threshold=0.19, # Reduced but still active threshold + boundary_margin=0.02 + ) + + # --- Relaxation Stage 3: Annealing --- + # Final polish with many iterations and extremely gentle forces. + self._relax_stage_vectorized( + iters=400, # Many iterations for a fine polish + step_size=0.00015, + repulsion_strength=0.001, + boundary_strength=0.005, + repulsion_threshold=0.18, # Final tight threshold + boundary_margin=0.005 + ) + + return self.centers + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles using the vectorized + CirclePacker class. + """ + packer = CirclePacker(n=26) + centers = packer.pack() + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This version + iteratively resolves conflicts until convergence for an accurate result. + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until no more changes occur. + for _ in range(300): + changes_made = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + ri_new = radii[i] * scale + rj_new = radii[j] * scale + + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i] = ri_new + radii[j] = rj_new + changes_made = True + + if not changes_made: + break + + return radii +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..0c81f0baccc23a39d80ae2c4343227c067f1e88f --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/job_log.err @@ -0,0 +1,11 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] +/home/tengxiao/pj/ShinkaEvolve/examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_93/main.py:65: UserWarning: 'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None. + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..330f01e97c8f558a21ae0b816bbda1b8a47aef72 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_93/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_93/results +Run 1/1 completed in 0.14 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.982168475555831 + public: {'centers_str': ' centers[0] = (0.0911, 0.0970)\n centers[1] = (0.2644, 0.0638)\n centers[2] = (0.5359, 0.0632)\n centers[3] = (0.7086, 0.0977)\n centers[4] = (0.9004, 0.1001)\n centers[5] = (0.0913, 0.3022)\n centers[6] = (0.2644, 0.3361)\n centers[7] = (0.5361, 0.3356)\n centers[8] = (0.7088, 0.3029)\n centers[9] = (0.9004, 0.3002)\n centers[10] = (0.0989, 0.5010)\n centers[11] = (0.2971, 0.5088)\n centers[12] = (0.5023, 0.5086)\n centers[13] = (0.7010, 0.5011)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.1000, 0.7001)\n centers[16] = (0.2998, 0.7004)\n centers[17] = (0.4999, 0.7004)\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.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.4000, 0.2000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.982168475555831} + visualization_path: + execution_time_mean: 0.1398479831404984 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..e432c4bcc2c645ed9f52eca1971889d8b92338bc --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.982168475555831, + "public": { + "centers_str": " centers[0] = (0.0911, 0.0970)\n centers[1] = (0.2644, 0.0638)\n centers[2] = (0.5359, 0.0632)\n centers[3] = (0.7086, 0.0977)\n centers[4] = (0.9004, 0.1001)\n centers[5] = (0.0913, 0.3022)\n centers[6] = (0.2644, 0.3361)\n centers[7] = (0.5361, 0.3356)\n centers[8] = (0.7088, 0.3029)\n centers[9] = (0.9004, 0.3002)\n centers[10] = (0.0989, 0.5010)\n centers[11] = (0.2971, 0.5088)\n centers[12] = (0.5023, 0.5086)\n centers[13] = (0.7010, 0.5011)\n centers[14] = (0.9001, 0.5000)\n centers[15] = (0.1000, 0.7001)\n centers[16] = (0.2998, 0.7004)\n centers[17] = (0.4999, 0.7004)\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.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.4000, 0.2000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.982168475555831 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_93/results/packing_viz.png", + "execution_time_mean": 0.1398479831404984, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..9f375220eff4993feac8663f6eabf5af54dc3800 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_93/search_replace.txt @@ -0,0 +1,172 @@ + +introduce_vortex_stage + + + +Based on my analysis of the visual feedback, the current arrangement is stuck in a suboptimal, grid-like local minimum. The circles, especially in the top half and along the right edge, form rigid rows, and the central cluster around the 26th circle is too symmetric and constrained. This indicates that the "Grid Breaking" stage, despite its aggressive repulsion, is not sufficiently disrupting the initial structure, allowing it to relax back into a slightly perturbed but still inefficient grid. + +To address this, I am introducing a "Vortex Stir" stage. This is a common technique in computational physics to break crystalline symmetries and explore amorphous, denser states. Instead of just pushing circles apart (a purely radial force), this new stage adds a tangential force component. This "swirl" or "stirring" motion is highly effective at shuffling circles out of their grid positions and preventing them from getting locked in simple repulsive standoffs. + +My changes are: +1. **Modify `_relax_stage_vectorized`**: I've added a `tangential_strength` parameter. When this is non-zero, the function calculates and applies a tangential force perpendicular to the line connecting circle centers, in addition to the standard radial repulsion. +2. **Update `pack()`**: I have replaced the ineffective "Grid Breaking" stage with the new "Vortex Stir" stage. This stage is run for 100 iterations with a significant `tangential_strength` to thoroughly shuffle the initial chaotic placement. The subsequent `Refinement` and `Annealing` stages remain, tasked with settling this new, more disordered configuration into a dense packing. + +This change directly targets the primary weakness observed in the visualization and should enable the system to explore more complex and efficient packing arrangements. + + + +<<<<<<< SEARCH + def _relax_stage_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin): + """ + Performs a force-directed relaxation stage using vectorized calculations + for high efficiency, enabling more iterations. + """ + for _ in range(iters): + # 1. Vectorized Circle-Circle Repulsion + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Create a mask for pairs of circles that are close enough to repel + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + # Calculate scalar force magnitudes + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + # Convert to force vectors and sum forces on each circle + force_vectors = force_scalar[:, :, np.newaxis] * np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + forces = np.sum(force_vectors, axis=1) + + # 2. Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + # 3. Apply forces and clip + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) +======= + def _relax_stage_vectorized(self, iters, step_size, repulsion_strength, + boundary_strength, repulsion_threshold, boundary_margin, tangential_strength=0.0): + """ + Performs a force-directed relaxation stage using vectorized calculations + for high efficiency. Can include a tangential 'vortex' force to break symmetries. + """ + for _ in range(iters): + # 1. Vectorized Circle-Circle Interaction + diff = self.centers[:, np.newaxis, :] - self.centers[np.newaxis, :, :] + dists = np.linalg.norm(diff, axis=2) + + # Mask for pairs of circles that are close enough to interact + mask = (dists > 1e-9) & (dists < repulsion_threshold) + + # Normalized difference vector, handling division by zero + normalized_diff = np.divide(diff, dists[:, :, np.newaxis], where=dists[:, :, np.newaxis] != 0) + + # --- Radial Repulsion Force --- + force_scalar = np.zeros_like(dists) + force_scalar[mask] = repulsion_strength * (repulsion_threshold - dists[mask]) / dists[mask] + radial_force_vectors = force_scalar[:, :, np.newaxis] * normalized_diff + + forces = np.sum(radial_force_vectors, axis=1) + + # --- Tangential Vortex Force (Optional) --- + if tangential_strength > 0: + # Tangential direction is 90-degree rotation of radial direction + tangential_dir = np.stack([-normalized_diff[:, :, 1], normalized_diff[:, :, 0]], axis=-1) + + # Use same falloff, but with tangential strength + tangential_scalar = np.zeros_like(dists) + tangential_scalar[mask] = tangential_strength * (repulsion_threshold - dists[mask]) / dists[mask] + + tangential_force_vectors = tangential_scalar[:, :, np.newaxis] * tangential_dir + forces += np.sum(tangential_force_vectors, axis=1) + + # 2. Vectorized Boundary Repulsion + forces[:, 0] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 0]) + forces[:, 0] -= boundary_strength * np.maximum(0, self.centers[:, 0] - (1 - boundary_margin)) + forces[:, 1] += boundary_strength * np.maximum(0, boundary_margin - self.centers[:, 1]) + forces[:, 1] -= boundary_strength * np.maximum(0, self.centers[:, 1] - (1 - boundary_margin)) + + # 3. Apply forces and clip + self.centers += step_size * forces + self.centers = np.clip(self.centers, 0.0, 1.0) +>>>>>>> REPLACE + + +<<<<<<< SEARCH + def pack(self): + """ + Orchestrates the entire packing process, from aggressive initialization + to multi-stage relaxation. + """ + # --- Initialization Stage --- + # Increased amplitude to shatter the initial grid structure. + self._initialize_grid_with_void( + void_center=np.array([0.4, 0.2]), + amplitude=0.08, # Increased from 0.04 to create more initial chaos + sigma=0.15 + ) + + # --- Relaxation Stage 1: Grid Breaking --- + # Increased threshold and strength to force circles out of grid alignment. + self._relax_stage_vectorized( + iters=200, # More iterations to handle the chaotic start + step_size=0.0025, + repulsion_strength=0.03, # Stronger push + boundary_strength=0.075, + repulsion_threshold=0.22, # > 0.2 grid spacing to break structure + boundary_margin=0.04 + ) + + # --- Relaxation Stage 2: Refinement --- + # Settle the now-disordered system into a dense configuration. + self._relax_stage_vectorized( + iters=250, # More iterations for better settling + step_size=0.0008, + repulsion_strength=0.005, + boundary_strength=0.025, + repulsion_threshold=0.19, # Reduced but still active threshold + boundary_margin=0.02 + ) +======= + def pack(self): + """ + Orchestrates the entire packing process, from aggressive initialization + to multi-stage relaxation including a vortex stage. + """ + # --- Initialization Stage --- + # Increased amplitude to shatter the initial grid structure. + self._initialize_grid_with_void( + void_center=np.array([0.4, 0.2]), + amplitude=0.08, # Increased from 0.04 to create more initial chaos + sigma=0.15 + ) + + # --- Relaxation Stage 1: Vortex Stir --- + # A new stage that applies tangential forces to "stir" the circles, + # breaking the grid symmetry more effectively than pure repulsion. + self._relax_stage_vectorized( + iters=100, + step_size=0.002, + repulsion_strength=0.02, + boundary_strength=0.05, + repulsion_threshold=0.20, + boundary_margin=0.04, + tangential_strength=0.015 # Induces a swirl + ) + + # --- Relaxation Stage 2: Refinement --- + # Settle the now-disordered system into a dense configuration. + self._relax_stage_vectorized( + iters=250, # More iterations for better settling + step_size=0.0008, + repulsion_strength=0.005, + boundary_strength=0.025, + repulsion_threshold=0.19, # Reduced but still active threshold + boundary_margin=0.02 + ) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d615b549e2de166a5ec375106a8afc3fad4d1882 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..216ae18273784c8e3d4ad0d100ded238ac987810 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/edit.diff @@ -0,0 +1,224 @@ +--- a/original.py ++++ b/original.py +@@ -1,174 +1,201 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + and applying a two-stage (exploration/refinement) force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Define the center of the void where the 26th circle will be placed. +- void_center = np.array([0.4, 0.4]) ++ # 2. Define an ASYMMETRIC center for the void. ++ # Using (0.4, 0.2) breaks initial symmetry, encouraging unique, denser packings. ++ void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + +- # Increased amplitude to create a larger initial void, allowing more room for exploration. +- amplitude = 0.05 ++ # Increased amplitude to create a larger initial void. ++ amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + +- # 4. Stage 1: High-Energy Exploration +- # This stage uses strong forces and a large step size to break the initial +- # grid structure and find a better global arrangement. +- exploration_iters = 250 ++ # Common boundary margin for all stages ++ boundary_margin = 0.04 ++ ++ # 4. Stage 1: High-Energy Exploration ("Shaking") ++ # Increased iterations and strength to break the grid structure more effectively. ++ exploration_iters = 300 + exploration_step_size = 0.003 +- exploration_repulsion_strength = 0.02 ++ exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 +- repulsion_threshold = 0.20 # Increased threshold to encourage movement and interaction. +- boundary_margin = 0.04 # Smaller margin to better utilize edges. ++ exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < repulsion_threshold: +- force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist ++ if 0 < dist < exploration_repulsion_threshold: ++ force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + +- # 5. Stage 2: Low-Energy Refinement +- # This stage uses more iterations with weaker forces and a smaller step size +- # to fine-tune the circle positions and settle into a dense local optimum. +- refinement_iters = 400 ++ # 5. Stage 2: Low-Energy Refinement ("Settling") ++ # A longer settling period with moderate forces to find a good basin of attraction. ++ refinement_iters = 500 + refinement_step_size = 0.0005 +- refinement_repulsion_strength = 0.008 ++ refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 +- +- # Use a slightly smaller repulsion threshold for refinement to allow tighter packing. + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces ++ centers = np.clip(centers, 0.0, 1.0) ++ ++ # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") ++ # A new stage for final micro-adjustments with very weak forces and many iterations. ++ annealing_iters = 800 ++ annealing_step_size = 0.0001 ++ annealing_repulsion_strength = 0.004 ++ annealing_boundary_strength = 0.02 ++ annealing_repulsion_threshold = 0.18 ++ ++ for _ in range(annealing_iters): ++ forces = np.zeros_like(centers) ++ for i in range(n): ++ for j in range(i + 1, n): ++ vec = centers[i] - centers[j] ++ dist = np.linalg.norm(vec) ++ if 0 < dist < annealing_repulsion_threshold: ++ force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist ++ force_vec = force_mag * (vec / dist) ++ forces[i] += force_vec ++ forces[j] -= force_vec ++ for i in range(n): ++ x, y = centers[i] ++ if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) ++ if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) ++ if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) ++ if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) ++ centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/main.py new file mode 100644 index 0000000000000000000000000000000000000000..e95d1e285705c70f889db7c743aaf28c023afa97 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/main.py @@ -0,0 +1,201 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + and applying a two-stage (exploration/refinement) force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define an ASYMMETRIC center for the void. + # Using (0.4, 0.2) breaks initial symmetry, encouraging unique, denser packings. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.06 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # Common boundary margin for all stages + boundary_margin = 0.04 + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # A new stage for final micro-adjustments with very weak forces and many iterations. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/original.py new file mode 100644 index 0000000000000000000000000000000000000000..cf9fe2e615d0d4c1ad0b452b234bd4ff689e21c6 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/original.py @@ -0,0 +1,174 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid + and applying a two-stage (exploration/refinement) force-directed relaxation. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with the 25 centers of a 5x5 grid. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Define the center of the void where the 26th circle will be placed. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void, allowing more room for exploration. + amplitude = 0.05 + sigma = 0.15 + + for i in range(25): + pos_vector = base_centers_25[i] - void_center + dist_sq = np.sum(pos_vector**2) + push_magnitude = amplitude * np.exp(-dist_sq / (2 * sigma**2)) + if np.linalg.norm(pos_vector) > 1e-9: + direction = pos_vector / np.linalg.norm(pos_vector) + displacement = direction * push_magnitude + deformed_centers_25[i] += displacement + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # 4. Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to break the initial + # grid structure and find a better global arrangement. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + repulsion_threshold = 0.20 # Increased threshold to encourage movement and interaction. + boundary_margin = 0.04 # Smaller margin to better utilize edges. + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to fine-tune the circle positions and settle into a dense local optimum. + refinement_iters = 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + # Use a slightly smaller repulsion threshold for refinement to allow tighter packing. + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Compute maximum valid radii for the refined configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + + Args: + centers: np.array of shape (n, 2) with (x, y) coordinates + + Returns: + np.array of shape (n) with radius of each circle + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries. + radii = np.zeros(n) + for i in range(n): + x, y = centers[i] + radii[i] = min(x, 1 - x, y, 1 - y) + + # Iteratively resolve overlaps between circles until no more changes occur. + # A high number of iterations ensures convergence for complex arrangements. + for _ in range(500): + changed_in_pass = False + # Check every pair of circles for overlap + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + + # If they overlap (with a small tolerance for floating point math) + if radii[i] + radii[j] > dist + 1e-12: + # Scale both radii down proportionally to resolve the overlap. + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: # Avoid division by zero + scale = dist / sum_r + radii[i] *= scale + radii[j] *= scale + else: # If both radii are already ~0, ensure they are exactly 0 + radii[i] = 0 + radii[j] = 0 + + changed_in_pass = True + + # If a full pass resulted in no changes, the packing is stable. + if not changed_in_pass: + break + + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..a7fd120c87a4ade186e18f3da9731671c8350980 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_94/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_94/results +Run 1/1 completed in 1.77 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9808569554223658 + 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} + private: {'reported_sum_of_radii': 1.9808569554223658} + visualization_path: + execution_time_mean: 1.7701397286728024 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..57801368855db509a98b3be607e96c9465194d2a --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9808569554223658, + "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 + }, + "private": { + "reported_sum_of_radii": 1.9808569554223658 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_94/results/packing_viz.png", + "execution_time_mean": 1.7701397286728024, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..da9ddadc5329cce6edd310b865771d0f9f7acdd1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_94/search_replace.txt @@ -0,0 +1,196 @@ +The current packing is trapped in a highly symmetric local optimum, a direct result of the `(0.4, 0.4)` void center. This leads to inefficient space usage, particularly in the central region where a large circle is surrounded by small, compressed circles. The previous high-scoring solutions successfully broke this symmetry by using an asymmetric void at `(0.4, 0.2)`. + +My strategy is to revert to the more successful approach by: +1. Re-introducing the asymmetric void to break the initial symmetry. +2. Replacing the current two-stage relaxation process with the more sophisticated and proven three-stage (Exploration, Refinement, Annealing) method. This adds a critical final "polishing" stage with very weak forces, allowing for micro-adjustments that are essential for maximizing the sum of radii. + +These changes are designed to escape the current symmetric trap and guide the simulation towards a denser, more complex, and higher-scoring configuration. + + +asymmetric_void_and_push + + +The visualization reveals a highly symmetric packing, which is a known trap and local optimum. To break this symmetry, I am reverting the void center to the asymmetric `(0.4, 0.2)` position, which proved successful in previous high-scoring versions. Simultaneously, I am increasing the initial Gaussian push `amplitude` to `0.06` to create a larger, more disrupted initial void, giving the relaxation algorithm a better, less-ordered starting configuration to work from. + + +<<<<<<< SEARCH + # 2. Define the center of the void where the 26th circle will be placed. + void_center = np.array([0.4, 0.4]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void, allowing more room for exploration. + amplitude = 0.05 +======= + # 2. Define an ASYMMETRIC center for the void. + # Using (0.4, 0.2) breaks initial symmetry, encouraging unique, denser packings. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the 25 grid points with a Gaussian repulsive push from the void center. + deformed_centers_25 = np.copy(base_centers_25) + + # Increased amplitude to create a larger initial void. + amplitude = 0.06 +>>>>>>> REPLACE + + +reinstate_three_stage_relaxation + + +The current two-stage relaxation is insufficient for fine-tuning. I am replacing it with the more robust three-stage process (Exploration, Refinement, Annealing) from a high-scoring ancestor. +1. **Exploration ("Shaking"):** Uses aggressive parameters (`iters=300`, `strength=0.025`) to thoroughly break the initial grid memory. +2. **Refinement ("Settling"):** A longer stage with moderate forces (`iters=500`, `strength=0.01`) to guide the circles toward a good basin of attraction. +3. **Annealing ("Polishing"):** A final, long stage with very weak forces (`iters=800`, `strength=0.004`, `step=0.0001`) to perform critical micro-adjustments and settle into a dense, stable local optimum. + + +<<<<<<< SEARCH + # 4. Stage 1: High-Energy Exploration + # This stage uses strong forces and a large step size to break the initial + # grid structure and find a better global arrangement. + exploration_iters = 250 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.02 + exploration_boundary_strength = 0.1 + repulsion_threshold = 0.20 # Increased threshold to encourage movement and interaction. + boundary_margin = 0.04 # Smaller margin to better utilize edges. + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < repulsion_threshold: + force_mag = exploration_repulsion_strength * (repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement + # This stage uses more iterations with weaker forces and a smaller step size + # to fine-tune the circle positions and settle into a dense local optimum. + refinement_iters = 400 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.008 + refinement_boundary_strength = 0.04 + + # Use a slightly smaller repulsion threshold for refinement to allow tighter packing. + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) +======= + # Common boundary margin for all stages + boundary_margin = 0.04 + + # 4. Stage 1: High-Energy Exploration ("Shaking") + # Increased iterations and strength to break the grid structure more effectively. + exploration_iters = 300 + exploration_step_size = 0.003 + exploration_repulsion_strength = 0.025 + exploration_boundary_strength = 0.1 + exploration_repulsion_threshold = 0.20 + + for _ in range(exploration_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += exploration_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += exploration_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - boundary_margin)) + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 5. Stage 2: Low-Energy Refinement ("Settling") + # A longer settling period with moderate forces to find a good basin of attraction. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += refinement_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += refinement_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 6. Stage 3: Ultra-Low-Energy Annealing ("Polishing") + # A new stage for final micro-adjustments with very weak forces and many iterations. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.18 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + force_vec = force_mag * (vec / dist) + forces[i] += force_vec + forces[j] -= force_vec + for i in range(n): + x, y = centers[i] + if x < boundary_margin: forces[i, 0] += annealing_boundary_strength * (boundary_margin - x) + if x > 1 - boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - boundary_margin)) + if y < boundary_margin: forces[i, 1] += annealing_boundary_strength * (boundary_margin - y) + if y > 1 - boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) +>>>>>>> REPLACE + \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dbccee05b08084357a552763e630d4ed0cf69fb1 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..95eaea1cc1a8110f2fa4b273f57503b35b84ece1 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_95/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_95/results +Run 1/1 completed in 1.87 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.9805618198066992 + public: {'centers_str': ' centers[0] = (0.0913, 0.0983)\n centers[1] = (0.2733, 0.0704)\n centers[2] = (0.5267, 0.0704)\n centers[3] = (0.7079, 0.0983)\n centers[4] = (0.9011, 0.1000)\n centers[5] = (0.0912, 0.3016)\n centers[6] = (0.2729, 0.3271)\n centers[7] = (0.5271, 0.3271)\n centers[8] = (0.7079, 0.3016)\n centers[9] = (0.9011, 0.3000)\n centers[10] = (0.0991, 0.5008)\n centers[11] = (0.2984, 0.5079)\n centers[12] = (0.5016, 0.5079)\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.7010)\n centers[17] = (0.5000, 0.7010)\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.1998)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.9805618198066992} + visualization_path: + execution_time_mean: 1.8674519383348525 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..83b5d2bec9a129be11953e3ef9f6cfb20951c955 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.9805618198066992, + "public": { + "centers_str": " centers[0] = (0.0913, 0.0983)\n centers[1] = (0.2733, 0.0704)\n centers[2] = (0.5267, 0.0704)\n centers[3] = (0.7079, 0.0983)\n centers[4] = (0.9011, 0.1000)\n centers[5] = (0.0912, 0.3016)\n centers[6] = (0.2729, 0.3271)\n centers[7] = (0.5271, 0.3271)\n centers[8] = (0.7079, 0.3016)\n centers[9] = (0.9011, 0.3000)\n centers[10] = (0.0991, 0.5008)\n centers[11] = (0.2984, 0.5079)\n centers[12] = (0.5016, 0.5079)\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.7010)\n centers[17] = (0.5000, 0.7010)\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.1998)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.9805618198066992 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_95/results/packing_viz.png", + "execution_time_mean": 1.8674519383348525, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/__pycache__/main.cpython-311.pyc b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..15676c47ce05cca68ac77f4ec08dd65699f29f23 Binary files /dev/null and b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/__pycache__/main.cpython-311.pyc differ diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/edit.diff b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/edit.diff new file mode 100644 index 0000000000000000000000000000000000000000..08a9b8f4addbdff6717315bd72efe138cb59bb6b --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/edit.diff @@ -0,0 +1,218 @@ +--- a/original.py ++++ b/original.py +@@ -1,198 +1,204 @@ + # EVOLVE-BLOCK-START + """Constructor-based circle packing for n=26 circles using Vortex Annealing""" + + import numpy as np + + + def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid, + then applying a novel three-stage relaxation: + 1. Exploration with a decaying tangential "vortex" force to break symmetry. + 2. Standard Refinement to settle the configuration. + 3. Ultra-fine Annealing to polish the final packing. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + +- # 2. Use an asymmetric void center, a critical insight from high-performing solutions. +- void_center = np.array([0.4, 0.2]) ++ # 2. Use an asymmetric void center, shifted to (0.3, 0.3) to distribute radii more evenly. ++ void_center = np.array([0.3, 0.3]) + + # 3. Deform the grid with a Gaussian push to create space for the 26th circle. + # A slightly increased amplitude creates a better initial void. + amplitude = 0.065 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # === STAGE 1: VORTEX EXPLORATION (Novelty) === + # This stage introduces a tangential force to rotate the configuration, + # breaking grid-lock and exploring more complex arrangements. The vortex + # strength decays over time. + exploration_iters = 350 + exploration_step_size = 0.0028 + exploration_repulsion_strength = 0.022 + exploration_boundary_strength = 0.1 + exploration_vortex_strength = 0.008 # Strength of the rotational force + exploration_repulsion_threshold = 0.20 + exploration_boundary_margin = 0.05 + vortex_center = np.array([0.5, 0.5]) + + for i_iter in range(exploration_iters): + forces = np.zeros_like(centers) + + # Standard Repulsion Forces + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + + # Decaying Vortex and Boundary Forces + current_vortex_strength = exploration_vortex_strength * (1.0 - i_iter / exploration_iters) + for i in range(n): + # Vortex Force (Tangential) + radial_vec = centers[i] - vortex_center + tangential_vec = np.array([-radial_vec[1], radial_vec[0]]) + forces[i] += current_vortex_strength * tangential_vec + + # Boundary Force + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # === STAGE 2: REFINEMENT === + # Standard low-energy settling phase without the vortex force. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 +- refinement_repulsion_threshold = 0.185 ++ refinement_repulsion_threshold_start = 0.195 # Start slightly higher ++ refinement_repulsion_threshold_end = 0.175 # Decay to a tighter threshold + refinement_boundary_margin = 0.03 + +- for _ in range(refinement_iters): ++ for i_iter in range(refinement_iters): + forces = np.zeros_like(centers) ++ current_refinement_repulsion_threshold = refinement_repulsion_threshold_start - (i_iter / refinement_iters) * \ ++ (refinement_repulsion_threshold_start - refinement_repulsion_threshold_end) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < refinement_repulsion_threshold: +- force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist ++ if 0 < dist < current_refinement_repulsion_threshold: ++ force_mag = refinement_repulsion_strength * (current_refinement_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # === STAGE 3: ANNEALING === +- # Ultra-fine polishing stage for maximal density. ++ # Ultra-fine polishing stage for maximal density with decaying repulsion. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 +- annealing_repulsion_threshold = 0.180 ++ annealing_repulsion_threshold_start = 0.185 # Start slightly higher than final target ++ annealing_repulsion_threshold_end = 0.170 # Decay to an even tighter threshold + annealing_boundary_margin = 0.01 + +- for _ in range(annealing_iters): ++ for i_iter in range(annealing_iters): + forces = np.zeros_like(centers) ++ current_annealing_repulsion_threshold = annealing_repulsion_threshold_start - (i_iter / annealing_iters) * \ ++ (annealing_repulsion_threshold_start - annealing_repulsion_threshold_end) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) +- if 0 < dist < annealing_repulsion_threshold: +- force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist ++ if 0 < dist < current_annealing_repulsion_threshold: ++ force_mag = annealing_repulsion_strength * (current_annealing_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute final radii for the optimized configuration. + radii = compute_max_radii(centers) + return centers, radii + + + def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until convergence. + for _ in range(500): + changed_in_pass = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + # Only update if there's a significant change + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changed_in_pass = True + if not changed_in_pass: + break + return radii + + + # EVOLVE-BLOCK-END + + + # This part remains fixed (not evolved) + def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/main.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/main.py new file mode 100644 index 0000000000000000000000000000000000000000..8353667f3751af7ed91d4f00f7c0e6b96770d529 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/main.py @@ -0,0 +1,204 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using Vortex Annealing""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid, + then applying a novel three-stage relaxation: + 1. Exploration with a decaying tangential "vortex" force to break symmetry. + 2. Standard Refinement to settle the configuration. + 3. Ultra-fine Annealing to polish the final packing. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Use an asymmetric void center, shifted to (0.3, 0.3) to distribute radii more evenly. + void_center = np.array([0.3, 0.3]) + + # 3. Deform the grid with a Gaussian push to create space for the 26th circle. + # A slightly increased amplitude creates a better initial void. + amplitude = 0.065 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # === STAGE 1: VORTEX EXPLORATION (Novelty) === + # This stage introduces a tangential force to rotate the configuration, + # breaking grid-lock and exploring more complex arrangements. The vortex + # strength decays over time. + exploration_iters = 350 + exploration_step_size = 0.0028 + exploration_repulsion_strength = 0.022 + exploration_boundary_strength = 0.1 + exploration_vortex_strength = 0.008 # Strength of the rotational force + exploration_repulsion_threshold = 0.20 + exploration_boundary_margin = 0.05 + vortex_center = np.array([0.5, 0.5]) + + for i_iter in range(exploration_iters): + forces = np.zeros_like(centers) + + # Standard Repulsion Forces + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + + # Decaying Vortex and Boundary Forces + current_vortex_strength = exploration_vortex_strength * (1.0 - i_iter / exploration_iters) + for i in range(n): + # Vortex Force (Tangential) + radial_vec = centers[i] - vortex_center + tangential_vec = np.array([-radial_vec[1], radial_vec[0]]) + forces[i] += current_vortex_strength * tangential_vec + + # Boundary Force + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # === STAGE 2: REFINEMENT === + # Standard low-energy settling phase without the vortex force. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold_start = 0.195 # Start slightly higher + refinement_repulsion_threshold_end = 0.175 # Decay to a tighter threshold + refinement_boundary_margin = 0.03 + + for i_iter in range(refinement_iters): + forces = np.zeros_like(centers) + current_refinement_repulsion_threshold = refinement_repulsion_threshold_start - (i_iter / refinement_iters) * \ + (refinement_repulsion_threshold_start - refinement_repulsion_threshold_end) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < current_refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (current_refinement_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # === STAGE 3: ANNEALING === + # Ultra-fine polishing stage for maximal density with decaying repulsion. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold_start = 0.185 # Start slightly higher than final target + annealing_repulsion_threshold_end = 0.170 # Decay to an even tighter threshold + annealing_boundary_margin = 0.01 + + for i_iter in range(annealing_iters): + forces = np.zeros_like(centers) + current_annealing_repulsion_threshold = annealing_repulsion_threshold_start - (i_iter / annealing_iters) * \ + (annealing_repulsion_threshold_start - annealing_repulsion_threshold_end) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < current_annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (current_annealing_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute final radii for the optimized configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until convergence. + for _ in range(500): + changed_in_pass = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + # Only update if there's a significant change + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changed_in_pass = True + if not changed_in_pass: + break + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/original.py b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/original.py new file mode 100644 index 0000000000000000000000000000000000000000..ee4dd906af24527f5f09cd8ffc02dfd7b7f99ade --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/original.py @@ -0,0 +1,198 @@ +# EVOLVE-BLOCK-START +"""Constructor-based circle packing for n=26 circles using Vortex Annealing""" + +import numpy as np + + +def construct_packing(): + """ + Constructs a high-density arrangement of 26 circles by deforming a 5x5 grid, + then applying a novel three-stage relaxation: + 1. Exploration with a decaying tangential "vortex" force to break symmetry. + 2. Standard Refinement to settle the configuration. + 3. Ultra-fine Annealing to polish the final packing. + + Returns: + Tuple of (centers, radii) + centers: np.array of shape (26, 2) with (x, y) coordinates + radii: np.array of shape (26) with radius of each circle + """ + n = 26 + centers = np.zeros((n, 2)) + + # 1. Start with a 5x5 grid for the first 25 circles. + x_coords = np.linspace(0.1, 0.9, 5) + y_coords = np.linspace(0.1, 0.9, 5) + xx, yy = np.meshgrid(x_coords, y_coords) + base_centers_25 = np.vstack([xx.ravel(), yy.ravel()]).T + + # 2. Use an asymmetric void center, a critical insight from high-performing solutions. + void_center = np.array([0.4, 0.2]) + + # 3. Deform the grid with a Gaussian push to create space for the 26th circle. + # A slightly increased amplitude creates a better initial void. + amplitude = 0.065 + sigma = 0.15 + + displacements = base_centers_25 - void_center + distances = np.linalg.norm(displacements, axis=1) + mask = distances > 1e-9 + + push_magnitudes = np.zeros(25) + push_magnitudes[mask] = amplitude * np.exp(-distances[mask]**2 / (2 * sigma**2)) + + if np.any(mask): + displacements[mask] /= distances[mask, np.newaxis] + + deformed_centers_25 = base_centers_25 + displacements * push_magnitudes[:, np.newaxis] + + centers[:25] = deformed_centers_25 + centers[25] = void_center + centers = np.clip(centers, 0.0, 1.0) + + # === STAGE 1: VORTEX EXPLORATION (Novelty) === + # This stage introduces a tangential force to rotate the configuration, + # breaking grid-lock and exploring more complex arrangements. The vortex + # strength decays over time. + exploration_iters = 350 + exploration_step_size = 0.0028 + exploration_repulsion_strength = 0.022 + exploration_boundary_strength = 0.1 + exploration_vortex_strength = 0.008 # Strength of the rotational force + exploration_repulsion_threshold = 0.20 + exploration_boundary_margin = 0.05 + vortex_center = np.array([0.5, 0.5]) + + for i_iter in range(exploration_iters): + forces = np.zeros_like(centers) + + # Standard Repulsion Forces + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < exploration_repulsion_threshold: + force_mag = exploration_repulsion_strength * (exploration_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + + # Decaying Vortex and Boundary Forces + current_vortex_strength = exploration_vortex_strength * (1.0 - i_iter / exploration_iters) + for i in range(n): + # Vortex Force (Tangential) + radial_vec = centers[i] - vortex_center + tangential_vec = np.array([-radial_vec[1], radial_vec[0]]) + forces[i] += current_vortex_strength * tangential_vec + + # Boundary Force + x, y = centers[i] + if x < exploration_boundary_margin: forces[i, 0] += exploration_boundary_strength * (exploration_boundary_margin - x) + if x > 1 - exploration_boundary_margin: forces[i, 0] -= exploration_boundary_strength * (x - (1 - exploration_boundary_margin)) + if y < exploration_boundary_margin: forces[i, 1] += exploration_boundary_strength * (exploration_boundary_margin - y) + if y > 1 - exploration_boundary_margin: forces[i, 1] -= exploration_boundary_strength * (y - (1 - exploration_boundary_margin)) + + centers += exploration_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # === STAGE 2: REFINEMENT === + # Standard low-energy settling phase without the vortex force. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + refinement_boundary_margin = 0.03 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # === STAGE 3: ANNEALING === + # Ultra-fine polishing stage for maximal density. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.180 + annealing_boundary_margin = 0.01 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # 7. Compute final radii for the optimized configuration. + radii = compute_max_radii(centers) + return centers, radii + + +def compute_max_radii(centers): + """ + Compute the maximum possible radii for each circle position + such that they don't overlap and stay within the unit square. This is + an iterative version that converges to a stable solution. + """ + n = centers.shape[0] + + # Initialize radii based on distance to the square's boundaries (vectorized). + radii = np.min([centers[:, 0], 1 - centers[:, 0], centers[:, 1], 1 - centers[:, 1]], axis=0) + + # Iteratively resolve overlaps between circles until convergence. + for _ in range(500): + changed_in_pass = False + for i in range(n): + for j in range(i + 1, n): + dist = np.linalg.norm(centers[i] - centers[j]) + if radii[i] + radii[j] > dist + 1e-12: + sum_r = radii[i] + radii[j] + if sum_r > 1e-12: + scale = dist / sum_r + # Only update if there's a significant change + ri_new, rj_new = radii[i] * scale, radii[j] * scale + if ri_new < radii[i] - 1e-12 or rj_new < radii[j] - 1e-12: + radii[i], radii[j] = ri_new, rj_new + changed_in_pass = True + if not changed_in_pass: + break + return radii + + +# EVOLVE-BLOCK-END + + +# This part remains fixed (not evolved) +def run_packing(): + """Run the circle packing constructor for n=26""" + centers, radii = construct_packing() + # Calculate the sum of radii + sum_radii = np.sum(radii) + return centers, radii, sum_radii \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/correct.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/correct.json new file mode 100644 index 0000000000000000000000000000000000000000..3253af2e0d1b8942bcb0602218b9caf2145945ab --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/correct.json @@ -0,0 +1,4 @@ +{ + "correct": true, + "error": null +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/job_log.err b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/job_log.err new file mode 100644 index 0000000000000000000000000000000000000000..345388018093ce84dec98ead3e182d85d46d64b2 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/job_log.err @@ -0,0 +1,9 @@ +/home/tengxiao/pj/ShinkaEvolve/.venv/lib/python3.11/site-packages/instructor/providers/gemini/client.py:5: FutureWarning: + +All support for the `google.generativeai` package has ended. It will no longer be receiving +updates or bug fixes. Please switch to the `google.genai` package as soon as possible. +See README for more details: + +https://github.com/google-gemini/deprecated-generative-ai-python/blob/main/README.md + + import google.generativeai as genai # type: ignore[import-not-found] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/job_log.out b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/job_log.out new file mode 100644 index 0000000000000000000000000000000000000000..d53b596527bee1b06775b24aa3111dfe7d08ec61 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/job_log.out @@ -0,0 +1,18 @@ +Evaluating program: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_99/main.py +Saving results to: examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_99/results +Run 1/1 completed in 1.88 seconds +Detailed packing data saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/extra.npz +Visualization saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/packing_viz.png +Correctness and error status saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/correct.json +Metrics saved to examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/metrics.json +Evaluation and Validation completed successfully. +Metrics: + combined_score: 1.8317542968467873 + public: {'centers_str': ' centers[0] = (0.1017, 0.0984)\n centers[1] = (0.3017, 0.0725)\n centers[2] = (0.5087, 0.0922)\n centers[3] = (0.7029, 0.1005)\n centers[4] = (0.9017, 0.1016)\n centers[5] = (0.0741, 0.2983)\n centers[6] = (0.9992, 1.0000)\n centers[7] = (0.5247, 0.3001)\n centers[8] = (0.7051, 0.3008)\n centers[9] = (0.9011, 0.3016)\n centers[10] = (0.0922, 0.5055)\n centers[11] = (0.2999, 0.5232)\n centers[12] = (0.5071, 0.5071)\n centers[13] = (0.7013, 0.5011)\n centers[14] = (0.9001, 0.5016)\n centers[15] = (0.0989, 0.6997)\n centers[16] = (0.2992, 0.7035)\n centers[17] = (0.4995, 0.7013)\n centers[18] = (0.6993, 0.7008)\n centers[19] = (0.8992, 0.7013)\n centers[20] = (0.0984, 0.8985)\n centers[21] = (0.2984, 0.8996)\n centers[22] = (0.4984, 0.9001)\n centers[23] = (0.6981, 0.9008)\n centers[24] = (0.8924, 0.8957)\n centers[25] = (0.0000, 0.0000)', 'num_circles': 26} + private: {'reported_sum_of_radii': 1.8317542968467873} + visualization_path: + execution_time_mean: 1.8805247410200536 + execution_time_std: 0.0 + num_valid_runs: 1 + num_invalid_runs: 0 + all_validation_errors: [] diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/metrics.json b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/metrics.json new file mode 100644 index 0000000000000000000000000000000000000000..e09797d6870592fae5f729e3d2d1ee03b8146404 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/metrics.json @@ -0,0 +1,16 @@ +{ + "combined_score": 1.8317542968467873, + "public": { + "centers_str": " centers[0] = (0.1017, 0.0984)\n centers[1] = (0.3017, 0.0725)\n centers[2] = (0.5087, 0.0922)\n centers[3] = (0.7029, 0.1005)\n centers[4] = (0.9017, 0.1016)\n centers[5] = (0.0741, 0.2983)\n centers[6] = (0.9992, 1.0000)\n centers[7] = (0.5247, 0.3001)\n centers[8] = (0.7051, 0.3008)\n centers[9] = (0.9011, 0.3016)\n centers[10] = (0.0922, 0.5055)\n centers[11] = (0.2999, 0.5232)\n centers[12] = (0.5071, 0.5071)\n centers[13] = (0.7013, 0.5011)\n centers[14] = (0.9001, 0.5016)\n centers[15] = (0.0989, 0.6997)\n centers[16] = (0.2992, 0.7035)\n centers[17] = (0.4995, 0.7013)\n centers[18] = (0.6993, 0.7008)\n centers[19] = (0.8992, 0.7013)\n centers[20] = (0.0984, 0.8985)\n centers[21] = (0.2984, 0.8996)\n centers[22] = (0.4984, 0.9001)\n centers[23] = (0.6981, 0.9008)\n centers[24] = (0.8924, 0.8957)\n centers[25] = (0.0000, 0.0000)", + "num_circles": 26 + }, + "private": { + "reported_sum_of_radii": 1.8317542968467873 + }, + "visualization_path": "examples/circle_packing/results/results_circle_packing_WITH_vision_20260116_011247/gen_99/results/packing_viz.png", + "execution_time_mean": 1.8805247410200536, + "execution_time_std": 0.0, + "num_valid_runs": 1, + "num_invalid_runs": 0, + "all_validation_errors": [] +} \ No newline at end of file diff --git a/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/search_replace.txt b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/search_replace.txt new file mode 100644 index 0000000000000000000000000000000000000000..e23f2846b47071e40afe6d2581a2b21d613d2948 --- /dev/null +++ b/examples_deprecated/circle_packing/results__debug/results_circle_packing_WITH_vision_20260116_011247/gen_99/search_replace.txt @@ -0,0 +1,139 @@ + +The current visualization clearly shows a single very large circle (index 25) dominating the packing, centered around the initial `void_center` at `(0.4, 0.2)`. This circle's large size likely comes at the expense of its neighbors, which are notably smaller, leading to inefficient overall packing. By shifting the `void_center` to a slightly more central but still asymmetric location `(0.3, 0.3)`, we aim to distribute the space more evenly among the circles. This adjustment should prevent one circle from becoming excessively large and allow its neighbors to grow, thereby improving the total sum of radii. This directly addresses the "Spot Inefficient Patterns" observation regarding the isolated large circle and its tiny neighbors. + + + +<<<<<<< SEARCH + # 2. Use an asymmetric void center, a critical insight from high-performing solutions. + void_center = np.array([0.4, 0.2]) +======= + # 2. Use an asymmetric void center, shifted to (0.3, 0.3) to distribute radii more evenly. + void_center = np.array([0.3, 0.3]) +>>>>>>> REPLACE + + + +To further refine the packing and push circles into tighter arrangements, we're introducing adaptive repulsion thresholds for the Refinement and Annealing stages. Instead of a fixed `repulsion_threshold`, the threshold will gradually decrease over the iterations of each stage. This dynamic approach allows for broader adjustments early in the stage, then progressively enforces stricter non-overlap conditions, leading to denser and more stable configurations. This aligns with the "Granular Hyperparameter Control" strategy and helps in "Ultra-Fine Tuning" the packing. The vortex exploration stage maintains a fixed repulsion threshold to prioritize exploration over micro-adjustment. + + + +<<<<<<< SEARCH + # === STAGE 2: REFINEMENT === + # Standard low-energy settling phase without the vortex force. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold = 0.185 + refinement_boundary_margin = 0.03 + + for _ in range(refinement_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (refinement_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # === STAGE 3: ANNEALING === + # Ultra-fine polishing stage for maximal density. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold = 0.180 + annealing_boundary_margin = 0.01 + + for _ in range(annealing_iters): + forces = np.zeros_like(centers) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (annealing_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) +======= + # === STAGE 2: REFINEMENT === + # Standard low-energy settling phase without the vortex force. + refinement_iters = 500 + refinement_step_size = 0.0005 + refinement_repulsion_strength = 0.01 + refinement_boundary_strength = 0.04 + refinement_repulsion_threshold_start = 0.195 # Start slightly higher + refinement_repulsion_threshold_end = 0.175 # Decay to a tighter threshold + refinement_boundary_margin = 0.03 + + for i_iter in range(refinement_iters): + forces = np.zeros_like(centers) + current_refinement_repulsion_threshold = refinement_repulsion_threshold_start - (i_iter / refinement_iters) * \ + (refinement_repulsion_threshold_start - refinement_repulsion_threshold_end) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < current_refinement_repulsion_threshold: + force_mag = refinement_repulsion_strength * (current_refinement_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + for i in range(n): + x, y = centers[i] + if x < refinement_boundary_margin: forces[i, 0] += refinement_boundary_strength * (refinement_boundary_margin - x) + if x > 1 - refinement_boundary_margin: forces[i, 0] -= refinement_boundary_strength * (x - (1 - refinement_boundary_margin)) + if y < refinement_boundary_margin: forces[i, 1] += refinement_boundary_strength * (refinement_boundary_margin - y) + if y > 1 - refinement_boundary_margin: forces[i, 1] -= refinement_boundary_strength * (y - (1 - refinement_boundary_margin)) + centers += refinement_step_size * forces + centers = np.clip(centers, 0.0, 1.0) + + # === STAGE 3: ANNEALING === + # Ultra-fine polishing stage for maximal density with decaying repulsion. + annealing_iters = 800 + annealing_step_size = 0.0001 + annealing_repulsion_strength = 0.004 + annealing_boundary_strength = 0.02 + annealing_repulsion_threshold_start = 0.185 # Start slightly higher than final target + annealing_repulsion_threshold_end = 0.170 # Decay to an even tighter threshold + annealing_boundary_margin = 0.01 + + for i_iter in range(annealing_iters): + forces = np.zeros_like(centers) + current_annealing_repulsion_threshold = annealing_repulsion_threshold_start - (i_iter / annealing_iters) * \ + (annealing_repulsion_threshold_start - annealing_repulsion_threshold_end) + for i in range(n): + for j in range(i + 1, n): + vec = centers[i] - centers[j] + dist = np.linalg.norm(vec) + if 0 < dist < current_annealing_repulsion_threshold: + force_mag = annealing_repulsion_strength * (current_annealing_repulsion_threshold - dist) / dist + forces[i] += force_mag * (vec / dist) + forces[j] -= force_mag * (vec / dist) + for i in range(n): + x, y = centers[i] + if x < annealing_boundary_margin: forces[i, 0] += annealing_boundary_strength * (annealing_boundary_margin - x) + if x > 1 - annealing_boundary_margin: forces[i, 0] -= annealing_boundary_strength * (x - (1 - annealing_boundary_margin)) + if y < annealing_boundary_margin: forces[i, 1] += annealing_boundary_strength * (annealing_boundary_margin - y) + if y > 1 - annealing_boundary_margin: forces[i, 1] -= annealing_boundary_strength * (y - (1 - annealing_boundary_margin)) + centers += annealing_step_size * forces + centers = np.clip(centers, 0.0, 1.0) +>>>>>>> REPLACE + \ No newline at end of file