# EVOLVE-BLOCK-START
import numpy as np
from scipy.optimize import minimize
def scaling_law_func(data_points, params):
X = np.atleast_2d(np.asarray(data_points))
n = X[:, 0].astype(float)
p = np.asarray(params)
if p.ndim == 1:
p = p[None, :]
if p.shape[1] < 4:
p = np.pad(p, ((0, 0), (0, 4 - p.shape[1])), 'constant')
L, A, a, n1 = p[:, 0], p[:, 1], p[:, 2], p[:, 3]
n_safe = np.maximum(n, 1e-12)
n1 = np.maximum(n1, 1e-12)
m = (n_safe[:, None] / n1[None, :])
y = L[None, :] + A[None, :] / (1.0 + np.power(m, np.maximum(a[None, :], 1e-8)))
return y[:, 0] if y.shape[1] == 1 else y
def fit_scaling_law(data_points, loss_values):
X = np.atleast_2d(np.asarray(data_points))
n = X[:, 0].astype(float)
y = np.asarray(loss_values)
Y = y[:, None] if y.ndim == 1 else y
N, T = Y.shape
lb, ub = 0.5, 6.0
eps = 1e-12
w = np.log1p(n)
w = w / (np.sum(w) + eps)
def hub(r, d=0.25):
ar = np.abs(r)
return np.where(ar <= d, 0.5 * r * r, d * (ar - 0.5 * d))
def pack(L, A, a, n1):
z = np.clip((L - lb) / (ub - lb), 1e-6, 1 - 1e-6)
t0 = np.log(z) - np.log1p(-z)
return np.array([t0, np.log(max(A, 1e-12)), np.log(max(a, 1e-12)), np.log(max(n1, 1e-12))])
def unpack(t):
z = 1.0 / (1.0 + np.exp(-t[0]))
L = lb + (ub - lb) * z
return L, np.exp(t[1]), np.exp(t[2]), np.exp(t[3])
def obj(th, yy):
L, A, a, n1 = unpack(th)
pred = scaling_law_func(n[:, None], [L, A, a, n1])
r = pred - yy
return np.sum(w * hub(r)) + 1e-6 * (th[1]**2 + th[2]**2 + th[3]**2)
P = np.zeros((T, 4))
order = np.argsort(n)
high_idx = order[-max(3, N // 4):]
for t in range(T):
yy = Y[:, t]
L0 = float(np.clip(np.percentile(yy[high_idx], 30), lb, ub))
A0 = float(np.clip(np.percentile(yy, 95) - L0, 1e-3, 10.0))
r = np.clip(yy - L0, 1e-6, A0 - 1e-6)
z = np.clip(A0 / r - 1.0, 1e-6, 1e6)
ln_n = np.log(np.maximum(n, 1.0))
ln_z = np.log(z)
try:
a_est, b_est = np.polyfit(ln_n, ln_z, 1)
a0 = float(np.clip(a_est, 0.05, 2.5))
n10 = float(np.clip(np.exp(-b_est / max(a0, 1e-8)), 100.0, 1e7))
except Exception:
a0, n10 = 0.3, 3e3
seeds = [
pack(L0, A0, a0, n10),
pack(L0 * 0.98, A0 * 1.2, max(0.07, a0 * 0.8), n10 * 0.7),
pack(L0 * 1.02, A0 * 0.8, min(2.2, a0 * 1.25), n10 * 1.6),
pack(np.clip(np.min(yy), lb, ub), A0 * 0.6, 0.4, np.exp(np.mean(np.log(np.maximum(n, 1.0)))))
]
best, bestv = seeds[0], np.inf
for s0 in seeds:
res = minimize(obj, s0, args=(yy,), method='L-BFGS-B', options={'maxiter': 300})
th = res.x if res.success else s0
v = obj(th, yy)
if v < bestv:
bestv, best = v, th
P[t] = np.array(unpack(best))
return P[0] if T == 1 else P
# EVOLVE-BLOCK-END