<jupyter_start><jupyter_text>Automatic derivative-free step estimationThis notebook contains some drafts of possible approaches to estimate reasonable derivative steps withoutprior knowledge about the derivatives.<jupyter_code>import numpy as np
import matplotlib.pyplot as plt

from autostep.strategies import dx_min_cut, dx_relative_evaluation_order
from autostep.numerical_derivatives import df_dx_numerical
def f(x):
#     return x * x * x - x * x + x - 5  # increasing derivative
#     return -x * x * x - x * x + x - 5  # decreasing derivative
    return np.sin(x) * np.exp(-x)  # non-monotonic case
#     return np.sin(x) + 1e14

def df_dx_exact(x):
#     return 3 * x * x - 2 * x + 1  # increasing derivative
#     return -3 * x * x - 2 * x + 1  # decreasing derivative
    return np.exp(-x) * (np.cos(x) - np.sin(x))  # non-monotonic case
#     return np.cos(x)<jupyter_output><empty_output><jupyter_text>Hard coded approachThis is the classical case. The proper step is estimated by trial and errors, changing the value of `num_of_points`.<jupyter_code>x_initial = 0.0
x_final = 5.0
num_of_points = 15
dx = (x_final - x_initial) / num_of_points
x_domain = np.linspace(x_initial, x_final, num_of_points)

dx
df_dx_analytical = df_dx_exact(x_domain)
df_dx_approx = df_dx_numerical(f, x_domain, dx)

assert len(df_dx_analytical) == len(df_dx_approx)
# NBVAL_IGNORE_OUTPUT
plt.figure(figsize=(8, 6))
plt.plot(x_domain, df_dx_analytical, "o-", label='exact')
plt.plot(x_domain, df_dx_approx, "x-", label='numerical')
plt.grid(True)
plt.legend()

plt.xlabel(r"$x$")
plt.ylabel(r"$\dfrac{d f}{d x}$")

plt.tight_layout()
plt.show()<jupyter_output><empty_output><jupyter_text>Automatic step sizeThe only prior knowledge required is a record of function evaluations.<jupyter_code>f_evaluations = f(x_domain)<jupyter_output><empty_output><jupyter_text>Approach 1: step size relative to the norm of the absolute minimum value of the function<jupyter_code># NBVAL_IGNORE_OUTPUT
dx1 = dx_relative_evaluation_order(f_evaluations)

dx1<jupyter_output><empty_output><jupyter_text>**REMARK:**This approach is not suitable when `x_final - x_initial < 1`. Solutions are under investigations! Suggestions are welcome!  Approach 2: minimum difference among all function evaluations recorded<jupyter_code># NBVAL_IGNORE_OUTPUT
dx2 = dx_min_cut(f_evaluations)

dx2<jupyter_output><empty_output><jupyter_text>Comparing the results<jupyter_code>df_dx_analytical = df_dx_exact(x_domain)
df_dx_approx1 = df_dx_numerical(f, x_domain, dx1)
df_dx_approx2 = df_dx_numerical(f, x_domain, dx2)

assert len(df_dx_analytical) == len(df_dx_approx1) == len(df_dx_approx2)
# NBVAL_IGNORE_OUTPUT
plt.figure(figsize=(8, 6))
plt.plot(x_domain, df_dx_analytical, "o-", label='exact')
plt.plot(x_domain, df_dx_approx1, "x-", label='approach 1')
plt.plot(x_domain, df_dx_approx2, "x-", label='approach 2')
plt.grid(True)
plt.legend()

plt.xlabel(r"$x$")
plt.ylabel(r"$\dfrac{d f}{d x}$")

plt.tight_layout()
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11645653616456536, 'fraction_numerical': 0.012607830126078301, 'mean_word_length': 6.044392523364486, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '484413', 'license': 'MIT', 'n_tokens_mistral': 1190, 'n_tokens_neox': 1115, 'n_words': 257, 'path': 'notebooks/derivative-free-step-estimation.ipynb', 'repo_name': 'volpatto/autostep', 'size': '3014'}