def run_all_benchmarks(method='forward', order=4, x_values=(0.1, 0.5, 1.0, 5), n_max=11, show_plot=True): epsilon = MinStepGenerator(num_steps=3, scale=None, step_nom=None) scales = {} for n in range(1, n_max): plt.figure(n) scale_n = scales.setdefault(n, []) # for (name, x) in itertools.product( function_names, x_values): for name in function_names: fun0, dfun = get_function(name, n) if dfun is None: continue fd = Derivative(fun0, step=epsilon, method=method, n=n, order=order) for x in x_values: r = benchmark(x=x, dfun=dfun, fd=fd, name=name, scales=None, show_plot=show_plot) print(r) scale = r['scale'] if np.isfinite(scale): scale_n.append(scale) plt.vlines(np.mean(scale_n), 1e-12, 1, 'r', linewidth=3) plt.vlines(np.median(scale_n), 1e-12, 1, 'b', linewidth=3) _print_summary(method, order, x_values, scales)
import numpy as np from jacobi import jacobi from numdifftools import Derivative # function of one variable with auxiliary argument; returns a vector def f(p, x): y = p + x return np.sin(y) / y def fp(x): return np.cos(x) / x - np.sin(x) / x**2 x = np.linspace(-10, 10, 1000) fpx = fp(x) fpx1, fpxe1 = jacobi(f, 0, x) fpx2 = Derivative(lambda p: f(p, x))(0) plt.figure(constrained_layout=True) plt.plot(x, np.abs(fpx1 / fpx - 1), ls="-", label="Jacobi") plt.plot(x, np.abs(fpx2 / fpx - 1), ls="--", label="numdifftools") plt.title("relative deviation of numerical from true derivative") plt.legend(title="f(x) = sin(x)/x", ncol=2) plt.semilogy() plt.ylim(1e-16, 1e-11) plt.axhline(np.finfo(float).resolution, color="k", ls="--") plt.savefig("doc/_static/precision.svg")
iters += 1 return incumbent, iters, acc, step def show_results(func, incumbent, iters, acc, step, time): print("min f: ", func) print("at x = ", incumbent) print("iters: ", iters) print("acc: ", acc) print("step: ", step) print("time (ms): ", time, "\n") f = lambda x: 2 * x**2 - 0.5 start_time = time.time() * 1000 incumbent, iters, acc, step = backtrack(dfx=Derivative(f), x0=3., step=1e-3) end_time = time.time() * 1000 show_results(f(incumbent), incumbent, iters, acc, step, time=end_time - start_time) f = lambda x: 2 * x**4 - 4 * x**2 + x - 0.5 x0s = [-2., -0.5, 0.5, 2.] for x0 in x0s: start_time = time.time() * 1000 incumbent, iters, acc, step = backtrack(dfx=Derivative(f), x0=x0, step=1e-3)
def _example3(x=0.0001, fun_name='cos', epsilon=None, method='central', scale=None, n=1, order=2): fun0, dfun = get_function(fun_name, n) if dfun is None: return dict(n=n, order=order, method=method, fun=fun_name, error=np.nan, scale=np.nan) fd = Derivative(fun0, step=epsilon, method=method, n=n, order=order) t = [] scales = np.arange(1.0, 35, 0.25) for scale in scales: fd.step.scale = scale try: val = fd(x) except Exception: val = np.nan t.append(val) t = np.array(t) tt = dfun(x) relativ_error = np.abs(t - tt) / (np.maximum(np.abs(tt), 1)) + 1e-16 # weights = np.ones((3,))/3 # relativ_error = convolve1d(relativ_error, weights) # smooth curve if np.isnan(relativ_error).all(): return dict(n=n, order=order, method=method, fun=fun_name, error=np.nan, scale=np.nan) if True: # False: # plt.semilogy(scales, relativ_error, label=fun_name) plt.vlines(default_scale(fd.method, n, order), np.nanmin(relativ_error), 1) plt.xlabel('scales') plt.ylabel('Relative error') txt = ['', "1'st", "2'nd", "3'rd", "4'th", "5'th", "6'th", "7th" ] + ["%d'th" % i for i in range(8, 25)] plt.title("The %s derivative using %s, order=%d" % (txt[n], method, order)) plt.legend(frameon=False, framealpha=0.5) plt.axis([min(scales), max(scales), np.nanmin(relativ_error), 1]) # plt.figure() # plt.show('hold') i = np.nanargmin(relativ_error) return dict(n=n, order=order, method=method, fun=fun_name, error=relativ_error[i], scale=scales[i])
for i, fi in enumerate(fn): t = {} t["jacobi"] = [] t["numdifftools"] = [] nmax = 5 n = (10**np.linspace(0, nmax, nmax + 1)).astype(int) f = eval("lambda x: " + fi, np.__dict__) for ni in n: print(i, ni) x = np.linspace(0.1, 10, ni) number = 500 // ni + 10 r = timeit(lambda: jacobi(lambda p: f(p + x), 0), number=number) / number t["jacobi"].append(r) number = 500 // ni + 1 r = timeit(lambda: Derivative(lambda p: f(p + x)) (0), number=number) / number t["numdifftools"].append(r) plt.sca(ax.flat[i]) for k, v in t.items(): ls = "-" if "jacobi" in k else "--" plt.plot(n, v, ls=ls, label=k) r = np.divide(t["numdifftools"], t["jacobi"]) plt.plot(n, r, ls=":", color="k", lw=3, label="time ratio") for ni, ri in zip(n, r): plt.text(ni, ri * 0.5, f"{ri:.0f}" if i != 3 else f"{ri:.1f}", va="top", ha="center") plt.legend(loc="upper left", frameon=False) plt.title(fi)
def _Rdd(self, theta): """2nd derivative of the surface equation in spherical coordinates: r=r\'\'(theta)""" return Derivative(self._R, derOrder=2)(theta)
def _Rd(self, theta): """1st derivative of the surface equation in spherical coordinates: r=r\'(theta)""" return Derivative(self._R)(theta)
def test_taylor_horner_deriv(x, coeffs, order): def f(x): return taylor_horner(x, coeffs) df = Derivative(f, n=order) assert_allclose(df(x), taylor_horner_deriv(x, coeffs, order), atol=1e-11)