"""Nelder-Mead in numpy (no scipy on this PC), for fitting part parameters to the picture.""" import numpy as np def nelder_mead(f, x0, step, iters=400, tol=1e-5, log=None): n = len(x0) pts = [np.array(x0, float)] for i in range(n): p = np.array(x0, float) p[i] += step[i] pts.append(p) vals = [f(p) for p in pts] for it in range(iters): order = np.argsort(vals) pts = [pts[i] for i in order] vals = [vals[i] for i in order] if log and it % 20 == 0: log(it, vals[0]) if abs(vals[-1] - vals[0]) < tol: break c = np.mean(pts[:-1], 0) xr = c + (c - pts[-1]) fr = f(xr) if fr < vals[0]: xe = c + 2 * (c - pts[-1]) fe = f(xe) if fe < fr: pts[-1], vals[-1] = xe, fe else: pts[-1], vals[-1] = xr, fr elif fr < vals[-2]: pts[-1], vals[-1] = xr, fr else: xc = c + 0.5 * (pts[-1] - c) if fr >= vals[-1] else c + 0.5 * (xr - c) fc = f(xc) if fc < min(fr, vals[-1]): pts[-1], vals[-1] = xc, fc else: for i in range(1, len(pts)): pts[i] = pts[0] + 0.5 * (pts[i] - pts[0]) vals[i] = f(pts[i]) i = int(np.argmin(vals)) return pts[i], vals[i]