Agent Conversation: google/gemini-3.1-pro-preview
Task: optimization-evolution-strategy
Evolutionary Optimization Strategy Design
Research Question
Design a novel combination of selection, crossover, and mutation operators (and/or a novel evolutionary loop) for continuous black-box optimization that outperforms standard approaches across multiple benchmark functions.
Background
Evolutionary algorithms (EAs) are population-based metaheuristics for black-box optimization. The three core operators — selection, crossover, and mutation — together with the overall evolutionary loop design, determine an EA's performance. Standard approaches include:
- Genetic Algorithms (GA): Tournament selection + Simulated Binary Crossover (SBX) + Polynomial Mutation
- CMA-ES: Adapts the covariance matrix of a multivariate Gaussian to guide search
- Differential Evolution (DE): Uses vector differences between population members for mutation
Each has strengths on different function landscapes (multimodal, ill-conditioned, high-dimensional), but no single strategy dominates all.
Task
Modify the editable section of custom_evolution.py (lines 87-225) to implement a novel or improved evolutionary strategy. You may modify:
custom_select(population, k, toolbox)— selection operatorcustom_crossover(ind1, ind2)— crossover/recombination operatorcustom_mutate(individual, lo, hi)— mutation operatorrun_evolution(...)— the full evolutionary loop (you can restructure the algorithm entirely)
The DEAP library (deap.base, deap.creator, deap.tools) is available. You may also use numpy, scipy, math, and random.
Interface
- Individuals: Lists of floats, each with a
.fitness.valuesattribute (tuple of one float for minimization). run_evolutionmust return(best_individual, fitness_history)wherefitness_historyis a list of best fitness per generation.- TRAIN_METRICS: Print
TRAIN_METRICS gen=G best_fitness=F avg_fitness=Aperiodically (every 50 generations). - Respect the function signature and return types — the evaluation harness below the editable section is fixed.
Evaluation
Strategies are evaluated on 4 benchmarks (all minimization, lower is better):
| Benchmark | Function | Dimensions | Domain | Global Minimum |
|---|---|---|---|---|
| rastrigin-30d | Rastrigin | 30 | [-5.12, 5.12] | 0 |
| rosenbrock-30d | Rosenbrock | 30 | [-5, 10] | 0 |
| ackley-30d | Ackley | 30 | [-32.768, 32.768] | 0 |
| rastrigin-100d | Rastrigin | 100 | [-5.12, 5.12] | 0 |
Metrics: best_fitness (final best value, lower is better) and convergence_gen (generation reaching near-final fitness).
Hints
- Consider adaptive operator selection or parameter control (e.g., adapting crossover/mutation rates during evolution).
- Hybrid approaches combining ideas from GA, DE, and ES can be effective.
- Elitism (preserving the best individuals across generations) often helps.
- For multimodal functions like R
Tool Input
1{
2 "op": "replace",
3 "start_line": 88,
4 "end_line": 225,
5 "filename": "deap/custom_evolution.py",
6 "content": "def custom_select(population: list, k: int, toolbox=None) -> list:\n \"\"\"Not used by the adaptive evolutionary loop directly.\"\"\"\n return population[:k]\n\ndef custom_crossover(ind1: list, ind2: list) -> Tuple[list, list]:\n \"\"\"Stubbed, crossover is handled dynamically within run_evolution.\"\"\"\n return ind1, ind2\n\ndef custom_mutate(individual: list, lo: float, hi: float) -> Tuple[list]:\n \"\"\"Stubbed, mutation is handled dynamically within run_evolution.\"\"\"\n return (individual,)\n\ndef run_evolution(\n evaluate_func: Callable,\n dim: int,\n lo: float,\n hi: float,\n pop_size: int,\n n_generations: int,\n cx_prob: float,\n mut_prob: float,\n seed: int,\n) -> Tuple[list, list]:\n \"\"\"Adaptive Eigen-Covariance Differential Evolution (AEC-DE).\n \n Combines Success-History Adaptive DE (L-SHADE) with adaptive operator selection\n between standard binomial crossover and eigen-basis crossover. This creates a \n scale-invariance and rotation-invariance strategy that learns the best operator\n proportion during search. Also uses Opposition-based initialization.\n \"\"\"\n random.seed(seed)\n np.random.seed(seed)\n\n N_init = pop_size\n N_min = 4\n \n # Opposition-Based Initialization\n pop1 = np.random.uniform(lo, hi, (N_init, dim))\n pop2 = lo + hi - pop1\n \n fit1 = np.array([evaluate_func(ind.tolist())[0] for ind in pop1])\n fit2 = np.array([evaluate_func(ind.tolist())[0] for ind in pop2])\n \n pop_comb = np.vstack([pop1, pop2])\n fit_comb = np.concatenate([fit1, fit2])\n \n best_idx = np.argsort(fit_comb)[:N_init]\n pop = pop_comb[best_idx]\n fitnesses = fit_comb[best_idx]\n \n # L-SHADE Memory\n H = 6\n M_CR = np.array([0.5] * H)\n M_F = np.array([0.5] * H)\n k_mem = 0\n \n archive = []\n \n P_eigen = 0.5 # Probability of using eigenvector-based crossover\n fitness_history = []\n \n for gen in range(n_generations):\n # Linear Population Size Reduction\n N_current = int(round(N_init - (N_init - N_min) * (gen / n_generations)))\n N_current = max(N_min, min(N_current, len(pop)))\n \n if N_current < len(pop):\n sorted_idx = np.argsort(fitnesses)\n pop = pop[sorted_idx[:N_current]]\n fitnesses = fitnesses[sorted_idx[:N_current]]\n \n # Covariance Matrix & Eigenbasis\n sorted_idx = np.argsort(fitnesses)\n best_half_idx = sorted_idx[:max(3, N_current // 2)]\n cov = np.cov(pop[best_half_idx].T)\n cov += np.eye(dim) * 1e-8\n eigenvalues, eigenvectors = np.linalg.eigh(cov)\n B = eigenvectors\n B_inv = B.T\n \n S_CR = []\n S_F = []\n delta_f = []\n \n delta_eigen = []\n delta_standard = []\n \n new_pop = np.zeros_like(pop)\n new_fitnesses = np.zeros(N_current)\n \n for i in range(N_current):\n # Parameter Sampling\n r_mem = random.randint(0, H - 1)\n \n # CR sampling\n m_cr = M_CR[r_mem]\n CR = np.random.normal(m_cr, 0.1)\n CR = np.clip(CR, 0.0, 1.0)\n \n # F sampling\n m_f = M_F[r_mem]\n while True:\n F = m_f + 0.1 * np.random.standard_cauchy()\n if F > 0:\n break\n F = min(F, 1.0)\n \n # current-to-pbest mutation\n p_min = 2.0 / N_current\n p = random.uniform(p_min, 0.2)\n n_pbest = max(1, int(round(p * N_current)))\n pbest_idx = sorted_idx[random.randint(0, n_pbest - 1)]\n x_pbest = pop[pbest_idx]\n \n x_i = pop[i]\n \n candidates = list(range(N_current))\n candidates.remove(i)\n r1 = random.choice(candidates)\n x_r1 = pop[r1]\n \n r2_candidates = list(range(N_current + len(archive)))\n r2_candidates.remove(i)\n if r1 in r2_candidates:\n r2_candidates.remove(r1)\n \n if len(r2_candidates) > 0:\n r2 = random.choice(r2_candidates)\n if r2 < N_current:\n x_r2 = pop[r2]\n else:\n x_r2 = archive[r2 - N_current]\n else:\n x_r2 = pop[random.choice(candidates)]\n \n v = x_i + F * (x_pbest - x_i) + F * (x_r1 - x_r2)\n \n # Adaptive Crossover\n use_eigen = (random.random() < P_eigen)\n \n j_rand = random.randint(0, dim - 1)\n mask = (np.random.rand(dim) < CR)\n mask[j_rand] = True\n \n if use_eigen:\n x_eig = B_inv @ x_i\n v_eig = B_inv @ v\n u_eig = np.where(mask, v_eig, x_eig)\n u = B @ u_eig\n else:\n u = np.where(mask, v, x_i)\n \n # Bound Handling\n out_of_bounds = (u < lo) | (u > hi)\n if np.any(out_of_bounds):\n u = np.where(u < lo, (x_i + lo) / 2.0, u)\n u = np.where(u > hi, (x_i + hi) / 2.0, u)\n \n u_fit_val = evaluate_func(u.tolist())[0]\n \n if u_fit_val <= fitnesses[i]:\n new_pop[i] = u\n new_fitnesses[i] = u_fit_val\n \n if u_fit_val < fitnesses[i]:\n delta = fitnesses[i] - u_fit_val\n S_CR.append(CR)\n S_F.append(F)\n delta_f.append(delta)\n archive.append(x_i)\n \n if use_eigen:\n delta_eigen.append(delta)\n else:\n delta_standard.append(delta)\n else:\n new_pop[i] = x_i\n new_fitnesses[i] = fitnesses[i]\n \n pop = new_pop\n fitnesses = new_fitnesses\n \n # Update P_eigen\n sum_eigen = sum(delta_eigen)\n sum_standard = sum(delta_standard)\n total_sum = sum_eigen + sum_standard\n if total_sum > 0:\n target_P_eigen = sum_eigen / total_sum\n P_eigen = 0.9 * P_eigen + 0.1 * target_P_eigen\n P_eigen = max(0.1, min(0.9, P_eigen))\n \n # Update archive size\n if len(archive) > N_init:\n archive = random.sample(archive, N_init)\n \n # Update M_CR, M_F memory\n if len(S_F) > 0:\n weights = np.array(delta_f) / (np.sum(delta_f) + 1e-10)\n m_f_new = np.sum(weights * np.array(S_F)**2) / (np.sum(weights * np.array(S_F)) + 1e-10)\n m_cr_new = np.sum(weights * np.array(S_CR))\n \n M_F[k_mem] = m_f_new\n if m_cr_new > 0:\n M_CR[k_mem] = m_cr_new\n \n k_mem = (k_mem + 1) % H\n \n best_fit = np.min(fitnesses)\n fitness_history.append(best_fit)\n \n if (gen + 1) % 50 == 0 or gen == 0:\n avg_fit = np.mean(fitnesses)\n print(\n f\"TRAIN_METRICS gen={gen+1} best_fitness={best_fit:.6e} \"\n f\"avg_fitness={avg_fit:.6e} P_eigen={P_eigen:.3f}\",\n flush=True,\n )\n\n # Return best individual\n best_idx = np.argmin(fitnesses)\n best_ind = creator.Individual(pop[best_idx].tolist())\n best_ind.fitness.values = (fitnesses[best_idx],)\n \n return best_ind, fitness_history"
7}OK: Replaced lines 88..225 with 224 line(s) in deap/custom_evolution.py. Editable range: 87–311.
[Current file: deap/custom_evolution.py | editable: 87–311 | total: 389 lines]
84| # EDITABLE SECTION — Design your evolutionary strategy below
85| # (lines 87 to 225)
86| # ================================================================
87
88 def custom_select(population: list, k: int, toolbox=None) -> list:
89 """Not used by the adaptive evolutionary loop directly."""
90 return population[:k]
91
92 def custom_crossover(ind1: list, ind2: list) -> Tuple[list, list]:
93 """Stubbed, crossover is handled dynamically within run_evolution."""
94 return ind1, ind2
95
96 def custom_mutate(individual: list, lo: float, hi: float) -> Tuple[list]:
97 """Stubbed, mutation is handled dynamically within run_evolution."""
98 return (individual,)
99
100 def run_evolution(
101 evaluate_func
[Test #1] (2 tests remaining; call submit(n=1) to submit this result) ## Seed 42 ### rastrigin-30d (scripts/rastrigin_30d.sh) Training progress (rastrigin-30d): TRAIN_METRICS gen=300 best_fitness=4.294725e+01 avg_fitness=6.083728e+01 P_eigen=0.100 TRAIN_METRICS gen=350 best_fitness=2.718301e+01 avg_fitness=4.481902e+01 P_eigen=0.100 TRAIN_METRICS gen=400 best_fitness=2.234556e+01 avg_fitness=3.194860e+01 P_eigen=0.100 TRAIN_METRICS gen=450 best_fitness=1.608998e+01 avg_fitness=2.159607e+01 P_eigen=0.100 TRAIN_METRICS gen=500 best_fitness=1.307924e+01 avg_fitness=1.379323e+01 P_eigen=0.100 best_fitness_rastrigin-30d: 1.307924e+01 convergence_gen_rastrigin-30d: 479 ### rosenbrock-30d (scripts/rosenbrock_30d.sh) Training progress (rosenbrock-30d): TRAIN_METRICS gen=300 best_fitness=2.216148e+01 avg_fitness=2.220821e+01 P_eigen=0.885 TRAIN_METRICS gen=350 best_fitness=2.112032e+01 avg_fitness=2.120266e+01 P_eigen=0.897 TRAIN_METRICS gen=400 best_fitness=2.040464e+01 avg_fitness=2.04746
Tool Input
1{
2 "op": "replace",
3 "start_line": 100,
4 "filename": "deap/custom_evolution.py",
5 "end_line": 311,
6 "content": "def run_evolution(\n evaluate_func: Callable,\n dim: int,\n lo: float,\n hi: float,\n pop_size: int,\n n_generations: int,\n cx_prob: float,\n mut_prob: float,\n seed: int,\n) -> Tuple[list, list]:\n from scipy.optimize import minimize\n random.seed(seed)\n np.random.seed(seed)\n \n N_init = pop_size\n N_min = max(4, dim // 4)\n \n # OBL Initialization\n pop1 = np.random.uniform(lo, hi, (N_init, dim))\n pop2 = lo + hi - pop1\n \n fit1 = np.array([evaluate_func(ind.tolist())[0] for ind in pop1])\n fit2 = np.array([evaluate_func(ind.tolist())[0] for ind in pop2])\n \n pop_comb = np.vstack([pop1, pop2])\n fit_comb = np.concatenate([fit1, fit2])\n \n best_idx = np.argsort(fit_comb)[:N_init]\n pop = pop_comb[best_idx]\n fitnesses = fit_comb[best_idx]\n \n # SHADE memory\n H = 6\n M_CR = np.array([0.5] * H)\n M_F = np.array([0.5] * H)\n k_mem = 0\n archive = []\n \n fitness_history = []\n \n # Adaptive Operator Selection Probabilities [Sep, Eigen, Std]\n op_probs = [0.34, 0.33, 0.33]\n \n for gen in range(n_generations):\n N_current = int(round(N_init - (N_init - N_min) * (gen / n_generations)))\n N_current = max(N_min, min(N_current, len(pop)))\n \n if N_current < len(pop):\n sorted_idx = np.argsort(fitnesses)\n pop = pop[sorted_idx[:N_current]]\n fitnesses = fitnesses[sorted_idx[:N_current]]\n \n if len(archive) > 0:\n poly_pop = np.vstack((pop, np.array(archive)))\n else:\n poly_pop = pop\n \n if len(poly_pop) >= max(10, dim):\n cov = np.cov(poly_pop.T) + np.eye(dim) * 1e-8\n eigenvalues, eigenvectors = np.linalg.eigh(cov)\n B = eigenvectors\n B_inv = B.T\n pop_cov_valid = True\n else:\n pop_cov_valid = False\n \n S_CR = []\n S_F = []\n delta_f = []\n op_scores = [0.0, 0.0, 0.0]\n \n sorted_idx = np.argsort(fitnesses)\n new_pop = np.zeros_like(pop)\n new_fitnesses = np.zeros(N_current)\n \n for i in range(N_current):\n r_mem = random.randint(0, H - 1)\n CR_sampled = np.clip(np.random.normal(M_CR[r_mem], 0.1), 0.0, 1.0)\n while True:\n F_sampled = M_F[r_mem] + 0.1 * np.random.standard_cauchy()\n if F_sampled > 0:\n break\n F_sampled = min(F_sampled, 1.0)\n \n op = random.choices([0, 1, 2], weights=op_probs)[0]\n \n if op == 0:\n CR = 0.05\n F = F_sampled\n use_eig = False\n elif op == 1:\n CR = CR_sampled\n F = F_sampled\n use_eig = pop_cov_valid\n else:\n CR = CR_sampled\n F = F_sampled\n use_eig = False\n \n p = random.uniform(2.0 / N_current, 0.2)\n n_pbest = max(1, int(round(p * N_current)))\n pbest_idx = sorted_idx[random.randint(0, n_pbest - 1)]\n x_pbest = pop[pbest_idx]\n \n x_i = pop[i]\n candidates = list(range(N_current))\n candidates.remove(i)\n r1 = random.choice(candidates)\n x_r1 = pop[r1]\n \n r2_candidates = list(range(N_current + len(archive)))\n r2_candidates.remove(i)\n if r1 in r2_candidates:\n r2_candidates.remove(r1)\n \n if len(r2_candidates) > 0:\n r2 = random.choice(r2_candidates)\n x_r2 = pop[r2] if r2 < N_current else archive[r2 - N_current]\n else:\n x_r2 = pop[random.choice(candidates)]\n \n v = x_i + F * (x_pbest - x_i) + F * (x_r1 - x_r2)\n \n j_rand = random.randint(0, dim - 1)\n mask = (np.random.rand(dim) < CR)\n mask[j_rand] = True\n \n if use_eig:\n x_eig = B_inv @ x_i\n v_eig = B_inv @ v\n u_eig = np.where(mask, v_eig, x_eig)\n u = B @ u_eig\n else:\n u = np.where(mask, v, x_i)\n \n out_of_bounds = (u < lo) | (u > hi)\n if np.any(out_of_bounds):\n u = np.where(u < lo, (x_i + lo) / 2.0, u)\n u = np.where(u > hi, (x_i + hi) / 2.0, u)\n \n u_fit = evaluate_func(u.tolist())[0]\n \n if u_fit <= fitnesses[i]:\n new_pop[i] = u\n new_fitnesses[i] = u_fit\n \n if u_fit < fitnesses[i]:\n delta = fitnesses[i] - u_fit\n S_CR.append(CR)\n S_F.append(F)\n delta_f.append(delta)\n archive.append(x_i)\n op_scores[op] += delta\n else:\n new_pop[i] = x_i\n new_fitnesses[i] = fitnesses[i]\n \n pop = new_pop\n fitnesses = new_fitnesses\n \n # Memetic Local Search every 50 generations to supercharge accurate convergence\n if (gen + 1) % 50 == 0 or gen == n_generations - 1:\n curr_best_idx = np.argmin(fitnesses)\n res = minimize(\n lambda x: evaluate_func(x.tolist())[0],\n pop[curr_best_idx],\n bounds=[(lo, hi)] * dim,\n method='L-BFGS-B',\n options={'maxfun': 1000, 'ftol': 1e-9}\n )\n if res.fun < fitnesses[curr_best_idx]:\n pop[curr_best_idx] = res.x\n fitnesses[curr_best_idx] = res.fun\n \n total_score = sum(op_scores)\n if total_score > 0:\n target_probs = [s / total_score for s in op_scores]\n op_probs = [0.8 * p + 0.2 * tp for p, tp in zip(op_probs, target_probs)]\n op_probs = [max(0.1, p) for p in op_probs]\n s_p = sum(op_probs)\n op_probs = [p / s_p for p in op_probs]\n \n if len(archive) > N_init:\n archive = random.sample(archive, N_init)\n \n if len(S_F) > 0:\n weights = np.array(delta_f) / (np.sum(delta_f) + 1e-10)\n M_F[k_mem] = np.sum(weights * np.array(S_F)**2) / (np.sum(weights * np.array(S_F)) + 1e-10)\n M_CR[k_mem] = np.sum(weights * np.array(S_CR))\n k_mem = (k_mem + 1) % H\n \n best_fit = np.min(fitnesses)\n fitness_history.append(best_fit)\n \n if (gen + 1) % 50 == 0 or gen == 0:\n avg_fit = np.mean(fitnesses)\n print(f\"TRAIN_METRICS gen={gen+1} best_fitness={best_fit:.6e} avg_fitness={avg_fit:.6e}\", flush=True)\n \n best_idx = np.argmin(fitnesses)\n toolbox = base.Toolbox()\n toolbox.register(\"individual\", creator.Individual, pop[best_idx].tolist())\n best_ind = toolbox.individual()\n best_ind.fitness.values = (fitnesses[best_idx],)\n \n return best_ind, fitness_history"
7}OK: Replaced lines 100..311 with 206 line(s) in deap/custom_evolution.py. Editable range: 87–305.
[Current file: deap/custom_evolution.py | editable: 87–305 | total: 383 lines]
84| # EDITABLE SECTION — Design your evolutionary strategy below
85| # (lines 87 to 225)
86| # ================================================================
87
88 def custom_select(population: list, k: int, toolbox=None) -> list:
89 """Not used by the adaptive evolutionary loop directly."""
90 return population[:k]
91
92 def custom_crossover(ind1: list, ind2: list) -> Tuple[list, list]:
93 """Stubbed, crossover is handled dynamically within run_evolution."""
94 return ind1, ind2
95
96 def custom_mutate(individual: list, lo: float, hi: float) -> Tuple[list]:
97 """Stubbed, mutation is handled dynamically within run_evolution."""
98 return (individual,)
99
100 def run_evolution(
101 evaluate_fun
[Test #2] (1 test remaining; call submit(n=2) to submit this result) ### rastrigin-30d (scripts/rastrigin_30d.sh) Training progress (rastrigin-30d): TRAIN_METRICS gen=300 best_fitness=2.984875e+01 avg_fitness=6.040822e+01 TRAIN_METRICS gen=350 best_fitness=2.885379e+01 avg_fitness=4.612737e+01 TRAIN_METRICS gen=400 best_fitness=1.790926e+01 avg_fitness=3.567119e+01 TRAIN_METRICS gen=450 best_fitness=8.954632e+00 avg_fitness=2.465406e+01 TRAIN_METRICS gen=500 best_fitness=5.969754e+00 avg_fitness=1.358169e+01 best_fitness_rastrigin-30d: 5.969754e+00 convergence_gen_rastrigin-30d: 500 ### rosenbrock-30d (scripts/rosenbrock_30d.sh) Training progress (rosenbrock-30d): TRAIN_METRICS gen=300 best_fitness=7.926182e+00 avg_fitness=1.547378e+01 TRAIN_METRICS gen=350 best_fitness=3.477899e+00 avg_fitness=1.133557e+01 TRAIN_METRICS gen=400 best_fitness=1.762897e-01 avg_fitness=7.499750e+00 TRAIN_METRICS gen=450 best_fitness=1.271064e-09 avg_fitness=3.902570e+00 TRAIN_METRICS gen=500 best_fitnes
Tool Input
1{
2 "start_line": 205,
3 "content": " cand_r1 = list(range(N_current))\n cand_r1.remove(i)\n r1 = random.choice(cand_r1)\n x_r1 = pop[r1]\n \n cand_r2 = list(range(N_current + len(archive)))\n cand_r2.remove(i)\n if r1 in cand_r2:\n cand_r2.remove(r1)\n \n if len(cand_r2) > 0:\n r2 = random.choice(cand_r2)\n x_r2 = pop[r2] if r2 < N_current else archive[r2 - N_current]\n else:\n x_r2 = pop[random.choice(cand_r1)]\n r2 = 0 # fallback\n \n if op == 0:\n CR = 0.0\n F = F_sampled\n use_eig = False\n \n cand_r3 = list(range(N_current))\n cand_r3.remove(i)\n if r1 in cand_r3: cand_r3.remove(r1)\n if r2 < N_current and r2 in cand_r3: cand_r3.remove(r2)\n \n r3 = random.choice(cand_r3) if cand_r3 else random.choice(cand_r1)\n x_r3 = pop[r3]\n \n v = x_r1 + F * (x_r2 - x_r3)\n else:\n if op == 1:\n CR = CR_sampled\n F = F_sampled\n use_eig = pop_cov_valid\n else:\n CR = CR_sampled\n F = F_sampled\n use_eig = False\n \n p = random.uniform(2.0 / N_current, 0.2)\n n_pbest = max(1, int(round(p * N_current)))\n pbest_idx = sorted_idx[random.randint(0, n_pbest - 1)]\n x_pbest = pop[pbest_idx]\n \n v = x_i + F * (x_pbest - x_i) + F * (x_r1 - x_r2)\n \n j_rand = random.randint(0, dim - 1)\n mask = (np.random.rand(dim) < CR)\n mask[j_rand] = True\n \n if use_eig:",
4 "filename": "deap/custom_evolution.py",
5 "op": "replace",
6 "end_line": 228
7}OK: Replaced lines 205..228 with 53 line(s) in deap/custom_evolution.py. Editable range: 87–334.
[Current file: deap/custom_evolution.py | editable: 87–334 | total: 412 lines]
84| # EDITABLE SECTION — Design your evolutionary strategy below
85| # (lines 87 to 225)
86| # ================================================================
87
88 def custom_select(population: list, k: int, toolbox=None) -> list:
89 """Not used by the adaptive evolutionary loop directly."""
90 return population[:k]
91
92 def custom_crossover(ind1: list, ind2: list) -> Tuple[list, list]:
93 """Stubbed, crossover is handled dynamically within run_evolution."""
94 return ind1, ind2
95
96 def custom_mutate(individual: list, lo: float, hi: float) -> Tuple[list]:
97 """Stubbed, mutation is handled dynamically within run_evolution."""
98 return (individual,)
99
100 def run_evolution(
101 evaluate_func
[Test #3] (0 tests remaining)
## Seed 42
### rastrigin-30d (scripts/rastrigin_30d.sh)
=== RASTRIGIN (dim=30) ===
Bounds: [-5.12, 5.12], Pop: 200, Gens: 500
Traceback (most recent call last):
File "/srv/home/bohanlyu/MLS-Bench/vendor/workspace/optimization-evolution-strategy/google_gemini-3.1-pro-preview_20260405_232405/deap/custom_evolution.py", line 412, in <module>
main()
File "/srv/home/bohanlyu/MLS-Bench/vendor/workspace/optimization-evolution-strategy/google_gemini-3.1-pro-preview_20260405_232405/deap/custom_evolution.py", line 384, in main
best_ind, fitness_history = run_evolution(
^^^^^^^^^^^^^^
File "/srv/home/bohanlyu/MLS-Bench/vendor/workspace/optimization-evolution-strategy/google_gemini-3.1-pro-preview_20260405_232405/deap/custom_evolution.py", line 263, in run_evolution
u = np.where(mask, v, x_i)
^^^
NameError: name 'x_i' is not defined
ERROR conda.cli.main_run:execute(142): `conda run bash /srv
Tool Input
1{
2 "op": "replace",
3 "filename": "deap/custom_evolution.py",
4 "content": "def custom_select(population: list, k: int, toolbox=None) -> list:\n return population[:k]\n\ndef custom_crossover(ind1: list, ind2: list) -> Tuple[list, list]:\n return ind1, ind2\n\ndef custom_mutate(individual: list, lo: float, hi: float) -> Tuple[list]:\n return (individual,)\n\ndef run_evolution(\n evaluate_func: Callable,\n dim: int,\n lo: float,\n hi: float,\n pop_size: int,\n n_generations: int,\n cx_prob: float,\n mut_prob: float,\n seed: int,\n) -> Tuple[list, list]:\n random.seed(seed)\n np.random.seed(seed)\n\n H = 6 # History size for adaptive DE\n N_init = pop_size\n N_min = max(4, dim)\n\n # DEAP toolbox setup specifically for evaluation\n toolbox = base.Toolbox()\n toolbox.register(\"individual\", make_individual, toolbox, dim, lo, hi)\n toolbox.register(\"population\", tools.initRepeat, list, toolbox.individual)\n toolbox.register(\"evaluate\", evaluate_func)\n\n # Initialize population randomly\n pop = toolbox.population(n=N_init)\n fitnesses = list(map(toolbox.evaluate, pop))\n \n pop_arr = np.array([list(ind) for ind in pop])\n fits_arr = np.array([fit[0] for fit in fitnesses])\n\n # Success History for F and CR\n M_F = np.ones(H) * 0.5\n M_CR = np.ones(H) * 0.5\n k_hist = 0\n\n archive = []\n fitness_history = []\n\n for gen in range(n_generations):\n # Linear Population Size Reduction (LPSR)\n ratio = gen / (n_generations - 1) if n_generations > 1 else 1.0\n N_current = int(np.round(N_init - (N_init - N_min) * ratio))\n\n # Trim population and archive\n if len(pop_arr) > N_current:\n sort_idx = np.argsort(fits_arr)\n keep_idx = sort_idx[:N_current]\n pop_arr = pop_arr[keep_idx]\n fits_arr = fits_arr[keep_idx]\n\n if len(archive) > N_current:\n archive = random.sample(archive, N_current)\n\n # Decide whether to use Eigen Crossover\n compute_eigen = (gen > 10 and M_CR.mean() > 0.1)\n p_eigen = 0.5 # Prob of choosing eigen vs standard binomial crossover\n B = None\n if compute_eigen:\n sort_idx = np.argsort(fits_arr)\n top_idx = sort_idx[:max(N_current // 2, dim + 1)]\n top_pop = pop_arr[top_idx]\n # Regularize covariance to prevent singularities\n C = np.cov(top_pop, rowvar=False) + np.eye(dim) * 1e-8\n try:\n # Eigendecomposition\n eigvals, eigvecs = np.linalg.eigh(C)\n B = eigvecs\n except np.linalg.LinAlgError:\n compute_eigen = False\n\n S_F, S_CR, delta_f = [], [], []\n trials = np.zeros_like(pop_arr)\n F_list, CR_list = [], []\n\n r_idx = np.random.randint(0, H, size=N_current)\n sort_idx = np.argsort(fits_arr)\n\n for i in range(N_current):\n # 1. Sample scaling factor F from Cauchy distribution\n r = r_idx[i]\n while True:\n F_i = M_F[r] + 0.1 * np.random.standard_cauchy()\n if F_i > 0:\n break\n F_i = min(F_i, 1.0)\n\n # 2. Sample crossover rate CR from Normal distribution\n CR_i = np.clip(np.random.normal(M_CR[r], 0.1), 0.0, 1.0)\n\n F_list.append(F_i)\n CR_list.append(CR_i)\n\n # 3. current-to-pbest/1 mutation strategy\n p_i = random.uniform(2.0 / N_current, 0.2)\n n_pbest = max(2, int(round(p_i * N_current)))\n pbest = pop_arr[random.choice(sort_idx[:n_pbest])]\n\n r1 = random.choice([x for x in range(N_current) if x != i])\n avail_r2 = [x for x in range(N_current + len(archive)) if x != i and x != r1]\n if not avail_r2: \n avail_r2 = [r1]\n r2_idx = random.choice(avail_r2)\n \n x_r2 = pop_arr[r2_idx] if r2_idx < N_current else archive[r2_idx - N_current]\n\n mutant = pop_arr[i] + F_i * (pbest - pop_arr[i]) + F_i * (pop_arr[r1] - x_r2)\n\n # 4. Crossover (Eigen or Standard Binomial)\n if compute_eigen and random.random() < p_eigen:\n x_prime = B.T @ pop_arr[i]\n v_prime = B.T @ mutant\n j_rand = random.randint(0, dim - 1)\n mask = (np.random.rand(dim) < CR_i)\n mask[j_rand] = True\n u_prime = np.where(mask, v_prime, x_prime)\n trial = B @ u_prime\n else:\n j_rand = random.randint(0, dim - 1)\n mask = (np.random.rand(dim) < CR_i)\n mask[j_rand] = True\n trial = np.where(mask, mutant, pop_arr[i])\n\n # 5. Boundary handling (midpoint bounce-back)\n for j in range(dim):\n if trial[j] < lo:\n trial[j] = (pop_arr[i][j] + lo) / 2.0\n elif trial[j] > hi:\n trial[j] = (pop_arr[i][j] + hi) / 2.0\n trials[i] = trial\n\n # Batch evaluation\n trial_fits = []\n for i in range(N_current):\n f = evaluate_func(trials[i].tolist())[0]\n trial_fits.append(f)\n\n # 6. Selection and Archive Update\n for i in range(N_current):\n if trial_fits[i] < fits_arr[i]:\n S_F.append(F_list[i])\n S_CR.append(CR_list[i])\n delta_f.append(fits_arr[i] - trial_fits[i])\n \n archive.append(pop_arr[i].copy())\n \n pop_arr[i] = trials[i]\n fits_arr[i] = trial_fits[i]\n elif trial_fits[i] == fits_arr[i]:\n pop_arr[i] = trials[i]\n\n # 7. Adaptive parameters update\n if S_F:\n weights = np.array(delta_f)\n w_sum = weights.sum()\n weights = weights / w_sum if w_sum > 0 else np.ones(len(S_F)) / len(S_F)\n\n M_F[k_hist] = np.sum(weights * np.array(S_F)**2) / (np.sum(weights * np.array(S_F)) + 1e-10)\n M_CR[k_hist] = np.sum(weights * np.array(S_CR))\n k_hist = (k_hist + 1) % H\n\n # 8. Track best fitness\n best_gen = np.min(fits_arr)\n if gen == 0:\n fitness_history.append(best_gen)\n else:\n fitness_history.append(min(best_gen, fitness_history[-1]))\n\n if (gen + 1) % 50 == 0 or gen == 0:\n avg_fit = np.mean(fits_arr)\n print(\n f\"TRAIN_METRICS gen={gen+1} best_fitness={fitness_history[-1]:.6e} avg_fitness={avg_fit:.6e}\",\n flush=True\n )\n\n # Format the best individual for DEAP compatibility\n best_idx = np.argmin(fits_arr)\n best_ind = creator.Individual(pop_arr[best_idx].tolist())\n best_ind.fitness.values = (fits_arr[best_idx],)\n\n return best_ind, fitness_history",
5 "after_line": 1,
6 "start_line": 88,
7 "end_line": 225
8}OK: Replaced lines 88..225 with 190 line(s) in deap/custom_evolution.py. Editable range: 87–277.
[Current file: deap/custom_evolution.py | editable: 87–277 | total: 355 lines]
84| # EDITABLE SECTION — Design your evolutionary strategy below
85| # (lines 87 to 225)
86| # ================================================================
87
88 def custom_select(population: list, k: int, toolbox=None) -> list:
89 return population[:k]
90
91 def custom_crossover(ind1: list, ind2: list) -> Tuple[list, list]:
92 return ind1, ind2
93
94 def custom_mutate(individual: list, lo: float, hi: float) -> Tuple[list]:
95 return (individual,)
96
97 def run_evolution(
98 evaluate_func: Callable,
99 dim: int,
100 lo: float,
101 hi: float,
102 pop_size: int,
103 n_generations: int,
104 cx_prob: float,
105 mut_prob: float,
106 seed: int,
107 ) -> Tu
[Test #1] (2 tests remaining; call submit(n=1) to submit this result) ### rastrigin-30d (scripts/rastrigin_30d.sh) Training progress (rastrigin-30d): TRAIN_METRICS gen=300 best_fitness=3.977689e+01 avg_fitness=5.669058e+01 TRAIN_METRICS gen=350 best_fitness=3.103979e+01 avg_fitness=4.146701e+01 TRAIN_METRICS gen=400 best_fitness=1.904571e+01 avg_fitness=3.007221e+01 TRAIN_METRICS gen=450 best_fitness=1.578308e+01 avg_fitness=2.151213e+01 TRAIN_METRICS gen=500 best_fitness=1.102181e+01 avg_fitness=1.452042e+01 best_fitness_rastrigin-30d: 1.102181e+01 convergence_gen_rastrigin-30d: 498 ### rosenbrock-30d (scripts/rosenbrock_30d.sh) Training progress (rosenbrock-30d): TRAIN_METRICS gen=300 best_fitness=2.104486e+01 avg_fitness=2.118451e+01 TRAIN_METRICS gen=350 best_fitness=1.940000e+01 avg_fitness=1.954140e+01 TRAIN_METRICS gen=400 best_fitness=1.782847e+01 avg_fitness=1.795073e+01 TRAIN_METRICS gen=450 best_fitness=1.663718e+01 avg_fitness=1.668233e+01 TRAIN_METRICS gen=500 best_fitne
Tool Input
1{
2 "start_line": 87,
3 "content": "def custom_select(population: list, k: int, toolbox=None) -> list:\n return population[:k]\n\ndef custom_crossover(ind1: list, ind2: list) -> Tuple[list, list]:\n return ind1, ind2\n\ndef custom_mutate(individual: list, lo: float, hi: float) -> Tuple[list]:\n return (individual,)\n\ndef run_evolution(\n evaluate_func: Callable,\n dim: int,\n lo: float,\n hi: float,\n pop_size: int,\n n_generations: int,\n cx_prob: float,\n mut_prob: float,\n seed: int,\n) -> Tuple[list, list]:\n from deap import cma as deap_cma\n \n random.seed(seed)\n np.random.seed(seed)\n \n lambda_cma = max(4, int(4 + 3 * math.log(dim)))\n n_de = pop_size - lambda_cma\n if n_de < 10:\n n_de = pop_size // 2\n lambda_cma = pop_size - n_de\n\n centroid = [(lo + hi) / 2.0] * dim\n sigma = (hi - lo) / 4.0\n strategy = deap_cma.Strategy(centroid=centroid, sigma=sigma, lambda_=lambda_cma)\n \n P_DE = [creator.Individual([random.uniform(lo, hi) for _ in range(dim)]) for _ in range(n_de)]\n for ind in P_DE:\n ind.fitness.values = evaluate_func(ind)\n \n mu_CR = 0.5\n mu_F = 0.5\n c_adapt = 0.1\n archive = []\n \n best_ever = None\n best_ever_fit = float('inf')\n fitness_history = []\n \n for gen in range(n_generations):\n try:\n cma_pop = strategy.generate(creator.Individual)\n except Exception:\n c_cen = best_ever[:] if best_ever else [(lo + hi) / 2.0] * dim\n strategy = deap_cma.Strategy(centroid=c_cen, sigma=sigma/2.0, lambda_=lambda_cma)\n cma_pop = strategy.generate(creator.Individual)\n \n de_trials = []\n F_list, CR_list = [], []\n \n sorted_de = sorted(P_DE, key=lambda x: x.fitness.values[0])\n n_pbest = max(1, int(0.05 * n_de))\n best_pool = sorted_de[:n_pbest]\n if best_ever is not None:\n best_pool.insert(0, best_ever)\n \n for i in range(n_de):\n CR_i = random.gauss(mu_CR, 0.1)\n CR_i = max(0.0, min(1.0, CR_i))\n \n while True:\n F_i = mu_F + 0.1 * np.random.standard_cauchy()\n if F_i > 0:\n F_i = min(1.0, F_i)\n break\n \n F_list.append(F_i)\n CR_list.append(CR_i)\n \n pbest = random.choice(best_pool)\n \n r1 = random.randint(0, n_de - 1)\n while r1 == i:\n r1 = random.randint(0, n_de - 1)\n \n union_len = n_de + len(archive)\n r2 = random.randint(0, union_len - 1)\n retries = 0\n while (r2 == i or r2 == r1) and retries < 10:\n r2 = random.randint(0, union_len - 1)\n retries += 1\n \n x_i = P_DE[i]\n x_r1 = P_DE[r1]\n x_r2 = P_DE[r2] if r2 < n_de else archive[r2 - n_de]\n \n trial = creator.Individual(x_i[:])\n j_rand = random.randint(0, dim - 1)\n for j in range(dim):\n if random.random() < CR_i or j == j_rand:\n trial[j] = x_i[j] + F_i * (pbest[j] - x_i[j]) + F_i * (x_r1[j] - x_r2[j])\n \n de_trials.append(trial)\n \n all_candidates = cma_pop + de_trials\n for ind in all_candidates:\n for j in range(dim):\n ind[j] = max(lo, min(hi, ind[j]))\n \n fitnesses = list(map(evaluate_func, all_candidates))\n for ind, fit in zip(all_candidates, fitnesses):\n ind.fitness.values = fit\n \n gen_best = min(all_candidates, key=lambda x: x.fitness.values[0])\n gen_best_fit = gen_best.fitness.values[0]\n if gen_best_fit < best_ever_fit:\n best_ever_fit = gen_best_fit\n best_ever = creator.Individual(gen_best[:])\n best_ever.fitness.values = gen_best.fitness.values\n \n fitness_history.append(best_ever_fit)\n \n try:\n strategy.update(cma_pop)\n except Exception:\n c_cen = best_ever[:] if best_ever else [(lo + hi) / 2.0] * dim\n strategy = deap_cma.Strategy(centroid=c_cen, sigma=sigma/2.0, lambda_=lambda_cma)\n \n S_F = []\n S_CR = []\n for i in range(n_de):\n if de_trials[i].fitness.values[0] <= P_DE[i].fitness.values[0]:\n if de_trials[i].fitness.values[0] < P_DE[i].fitness.values[0]:\n archive.append(creator.Individual(P_DE[i][:]))\n S_F.append(F_list[i])\n S_CR.append(CR_list[i])\n P_DE[i] = de_trials[i]\n \n while len(archive) > n_de:\n archive.pop(random.randint(0, len(archive) - 1))\n \n if S_F:\n sum_f = sum(S_F)\n if sum_f > 1e-6:\n mu_F = (1 - c_adapt) * mu_F + c_adapt * (sum(f**2 for f in S_F) / sum_f)\n mu_CR = (1 - c_adapt) * mu_CR + c_adapt * (sum(S_CR) / len(S_CR))\n \n if (gen + 1) % 50 == 0 or gen == 0:\n avg_fit = sum(ind.fitness.values[0] for ind in P_DE) / len(P_DE)\n print(f\"TRAIN_METRICS gen={gen+1} best_fitness={best_ever_fit:.6e} avg_fitness={avg_fit:.6e}\", flush=True)\n \n return best_ever, fitness_history",
4 "filename": "deap/custom_evolution.py",
5 "op": "replace",
6 "end_line": 225
7}OK: Replaced lines 87..225 with 151 line(s) in deap/custom_evolution.py. Editable range: 87–237.
[Current file: deap/custom_evolution.py | editable: 87–237 | total: 315 lines]
84| # EDITABLE SECTION — Design your evolutionary strategy below
85| # (lines 87 to 225)
86| # ================================================================
87 def custom_select(population: list, k: int, toolbox=None) -> list:
88 return population[:k]
89
90 def custom_crossover(ind1: list, ind2: list) -> Tuple[list, list]:
91 return ind1, ind2
92
93 def custom_mutate(individual: list, lo: float, hi: float) -> Tuple[list]:
94 return (individual,)
95
96 def run_evolution(
97 evaluate_func: Callable,
98 dim: int,
99 lo: float,
100 hi: float,
101 pop_size: int,
102 n_generations: int,
103 cx_prob: float,
104 mut_prob: float,
105 seed: int,
106 ) -> Tuple[list,