| """ |
| Evolutionary search over step function PROGRAMS, inspired by alphaevolve. |
| |
| The key insight: alphaevolve evolves CODE that generates step functions. |
| This means the optimal function might have a specific ALGORITHMIC structure. |
| |
| Let's search over step function programs parameterized by: |
| 1. Number of steps K |
| 2. Height formula: h_i = f(i, K, params) for some simple formula |
| 3. Width formula: w_i = g(i, K, params) |
| |
| Examples of formulas: |
| - h_i = a * sin(b * i/K + c)² (sinusoidal) |
| - h_i = a * (i/K)^b (power law) |
| - h_i = a * exp(-b * (i/K - c)²) (Gaussian) |
| - h_i = a if i in S else 0 (indicator of set S) |
| """ |
| import numpy as np |
| from scipy.optimize import minimize, differential_evolution |
| import time |
|
|
| def compute_c1_fft(f_values, dx): |
| f = np.maximum(f_values, 0.0) |
| N = len(f) |
| M = 2 * N |
| fft_f = np.fft.rfft(f, n=M) |
| conv = np.fft.irfft(fft_f * fft_f, n=M) * dx |
| integral_sq = (np.sum(f) * dx) ** 2 |
| if integral_sq < 1e-20: |
| return 1e10 |
| return float(np.max(conv) / integral_sq) |
|
|
| def compute_c1_smooth_and_grad(f, N, dx, alpha=200.0): |
| M = 2 * N |
| fft_f = np.fft.rfft(f, n=M) |
| conv = np.fft.irfft(fft_f * fft_f, n=M) * dx |
| integral = np.sum(f) * dx |
| if integral < 1e-15: |
| return 1e10, np.zeros(N) |
| integral_sq = integral ** 2 |
| max_val = np.max(conv) |
| shifted = conv - max_val |
| mask = shifted > -50.0 / alpha |
| weights = np.zeros_like(conv) |
| weights[mask] = np.exp(alpha * shifted[mask]) |
| sum_w = np.sum(weights) |
| if sum_w < 1e-30: |
| weights[np.argmax(conv)] = 1.0 |
| sum_w = 1.0 |
| smooth_max = max_val + np.log(sum_w) / alpha |
| softmax_w = weights / sum_w |
| c1 = smooth_max / integral_sq |
| fft_sw = np.fft.rfft(softmax_w, n=M) |
| fft_fp = np.fft.rfft(f, n=M) |
| corr = np.fft.irfft(fft_sw * np.conj(fft_fp), n=M) |
| grad_f = 2.0 * corr[:N] * dx / integral_sq - 2.0 * smooth_max * dx / (integral**3) |
| return c1, grad_f |
|
|
| def opt(params, N, dx, alpha, maxiter): |
| def obj(p, a=alpha): |
| f = p ** 2 |
| c1, g = compute_c1_smooth_and_grad(f, N, dx, a) |
| return c1, g * 2 * p |
| result = minimize(obj, params, jac=True, method='L-BFGS-B', |
| options={'maxiter': maxiter, 'ftol': 1e-16, 'gtol': 1e-15}) |
| return result.x |
|
|
| def full_opt_at_N(f_init, N): |
| dx = 0.5 / N |
| params = np.sqrt(np.maximum(f_init, 0.0) + 1e-12) |
| for alpha in [0.5, 5.0, 50.0, 500.0, 5000.0, 50000.0]: |
| params = opt(params, N, dx, alpha, 2000) |
| |
| for _ in range(3): |
| for alpha in [0.5, 2.0, 10.0]: |
| params = opt(params, N, dx, alpha, 300) |
| for alpha in [100.0, 1000.0, 10000.0, 100000.0]: |
| params = opt(params, N, dx, alpha, 1000) |
| f_out = params ** 2 |
| return f_out, compute_c1_fft(f_out, dx) |
|
|
|
|
| |
| N_eval = 5000 |
| t0 = time.time() |
| best_c1 = np.inf |
| best_f = None |
|
|
| |
| |
| print("=== Sinusoidal step heights ===") |
| for K in [20, 30, 50, 75, 100]: |
| for freq in range(1, 10): |
| bounds = [(0.01, 5.0), (0.01, 5.0), (0, 2*np.pi)] |
|
|
| def make_f(params, K=K, freq=freq): |
| A, B, phase = params |
| i = np.arange(K) |
| heights = A + B * np.sin(2*np.pi*freq*i/K + phase)**2 |
| heights = np.maximum(heights, 0.0) |
| |
| f = np.repeat(heights, N_eval // K + 1)[:N_eval] |
| return f |
|
|
| def obj(params, K=K, freq=freq): |
| f = make_f(params, K, freq) |
| return compute_c1_fft(f, 0.5/N_eval) |
|
|
| result = differential_evolution(obj, bounds, maxiter=200, seed=42, tol=1e-12) |
| if result.fun < best_c1: |
| f_step = make_f(result.x) |
| f_opt, c1 = full_opt_at_N(f_step, N_eval) |
| if c1 < best_c1: |
| best_c1 = c1 |
| best_f = f_opt.copy() |
| print(f" K={K} freq={freq}: C1 = {c1:.10f} ***") |
|
|
| |
| print("\n=== Power law + support fraction ===") |
| for K in [30, 50, 100]: |
| for power in np.linspace(0.2, 3.0, 8): |
| for frac in np.linspace(0.3, 1.0, 8): |
| i = np.arange(K) |
| heights = (i + 1.0) ** (-power) |
| |
| |
| for ordering in ['asc', 'desc', 'interleave', 'random']: |
| if ordering == 'asc': |
| h = np.sort(heights) |
| elif ordering == 'desc': |
| h = np.sort(heights)[::-1] |
| elif ordering == 'interleave': |
| h_sorted = np.sort(heights) |
| h = np.zeros_like(h_sorted) |
| h[::2] = h_sorted[:len(h[::2])] |
| h[1::2] = h_sorted[len(h[::2]):][::-1] |
| else: |
| np.random.seed(42 + K + int(power*10)) |
| h = heights.copy() |
| np.random.shuffle(h) |
|
|
| |
| n_active = max(1, int(K * frac)) |
| h[n_active:] = 0.0 |
|
|
| f = np.repeat(h, N_eval // K + 1)[:N_eval] |
| c1_raw = compute_c1_fft(f, 0.5/N_eval) |
|
|
| if c1_raw < 2.0: |
| f_opt, c1 = full_opt_at_N(f, N_eval) |
| if c1 < best_c1: |
| best_c1 = c1 |
| best_f = f_opt.copy() |
| print(f" K={K} power={power:.1f} frac={frac:.1f} {ordering}: C1 = {c1:.10f} ***") |
| break |
|
|
| elapsed = time.time() - t0 |
| print(f"\nPhase 1 complete: best C1 = {best_c1:.10f} ({elapsed:.0f}s)") |
|
|
| |
| print("\n=== Number-theoretic binary patterns ===") |
| for p in [31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]: |
| |
| qr = set() |
| for a in range(p): |
| qr.add((a * a) % p) |
|
|
| |
| h = np.array([1.0 if i in qr else 0.0 for i in range(p)]) |
| f = np.repeat(h, N_eval // p + 1)[:N_eval] |
| f_opt, c1 = full_opt_at_N(f, N_eval) |
| if c1 < best_c1: |
| best_c1 = c1 |
| best_f = f_opt.copy() |
| print(f" QR p={p}: C1 = {c1:.10f} ***") |
|
|
| |
| h_nqr = 1.0 - h |
| h_nqr[0] = 0.0 |
| f = np.repeat(h_nqr, N_eval // p + 1)[:N_eval] |
| f_opt, c1 = full_opt_at_N(f, N_eval) |
| if c1 < best_c1: |
| best_c1 = c1 |
| best_f = f_opt.copy() |
| print(f" NQR p={p}: C1 = {c1:.10f} ***") |
|
|
| |
| for h_val in [0.5, 1.0, 2.0]: |
| h_leg = np.zeros(p) |
| for i in range(p): |
| if i in qr and i > 0: |
| h_leg[i] = h_val |
| elif i > 0: |
| h_leg[i] = 1.0 |
| f = np.repeat(h_leg, N_eval // p + 1)[:N_eval] |
| f_opt, c1 = full_opt_at_N(f, N_eval) |
| if c1 < best_c1: |
| best_c1 = c1 |
| best_f = f_opt.copy() |
| print(f" Leg p={p} h={h_val}: C1 = {c1:.10f} ***") |
|
|
| elapsed = time.time() - t0 |
| print(f"\nFinal best: C1 = {best_c1:.10f} ({elapsed:.0f}s)") |
| print(f"Score: {1.5052939684401607 / best_c1:.10f}") |
|
|
| |
| f_existing = np.load('/workspace/best_f_5000.npy') |
| c1_existing = compute_c1_fft(f_existing, 0.5/len(f_existing)) |
| print(f"Existing best at N=5000: C1 = {c1_existing:.10f}") |
| if best_c1 < c1_existing: |
| np.save('/workspace/best_f_5000_evolve.npy', best_f) |
| print("NEW BEST! Saved.") |
|
|