.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_example/plot_shi_xie_xuan_nocedal_general_benchmark.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_example_plot_shi_xie_xuan_nocedal_general_benchmark.py: Benchmark Shi, Xie, Xuan & Nocedal's general method =================================================== The goal of this example is to benchmark the :class:`~numericalderivative.ShiXieXuanNocedalGeneral` class on a collection of test problems. These problems are created by the :meth:`~numericalderivative.build_benchmark()` static method, which returns a list of problems. .. GENERATED FROM PYTHON SOURCE LINES 16-21 .. code-block:: Python import numpy as np import pylab as pl import tabulate import numericalderivative as nd .. GENERATED FROM PYTHON SOURCE LINES 22-24 Compute the first derivative ---------------------------- .. GENERATED FROM PYTHON SOURCE LINES 24-87 .. code-block:: Python class ShiXieXuanNocedalGeneralMethod: def __init__( self, relative_precision, initial_step, differentiation_order=1, formula_accuracy=2, direction="central", ): """ Create a ShiXieXuanNocedalGeneral method to compute the approximate first derivative Parameters ---------- relative_precision : float, > 0, optional The relative precision of evaluation of f. initial_step : float, > 0 The initial step in the algorithm. """ self.relative_precision = relative_precision self.initial_step = initial_step self.differentiation_order = differentiation_order self.formula_accuracy = formula_accuracy self.direction = direction def compute_derivative(self, function, x): """ Compute the first derivative using ShiXieXuanNocedal Parameters ---------- function : function The function x : float The test point Returns ------- f_derivative_approx : float The approximate value of the first derivative of the function at point x number_of_function_evaluations : int The number of function evaluations. """ formula = nd.GeneralFiniteDifference( function, x, self.differentiation_order, self.formula_accuracy, self.direction, ) absolute_precision = abs(function(x)) * self.relative_precision algorithm = nd.ShiXieXuanNocedalGeneral( formula, absolute_precision, ) step, _ = algorithm.find_step(self.initial_step) f_derivative_approx = algorithm.compute_derivative(step) number_of_function_evaluations = algorithm.get_number_of_function_evaluations() return f_derivative_approx, number_of_function_evaluations .. GENERATED FROM PYTHON SOURCE LINES 88-90 The next example computes the approximate derivative on the :class:`~numericalderivative.ExponentialProblem`. .. GENERATED FROM PYTHON SOURCE LINES 92-133 .. code-block:: Python initial_step = 1.0e0 problem = nd.ExponentialProblem() print(problem) function = problem.get_function() x = problem.get_x() differentiation_order = 1 # First derivative formula_accuracy = 2 # Order 2 formula = nd.GeneralFiniteDifference( function, x, differentiation_order, formula_accuracy, direction="central", # Central formula ) algorithm = nd.ShiXieXuanNocedalGeneral( formula, verbose=True, ) third_derivative = problem.get_third_derivative() third_derivative_value = third_derivative(x) optimal_step, absolute_error = nd.FirstDerivativeCentral.compute_step( third_derivative_value ) print("Exact h* = %.3e" % (optimal_step)) function = problem.get_function() first_derivative = problem.get_first_derivative() x = 1.0 relative_precision = 1.0e-15 absolute_precision = abs(function(x)) * relative_precision method = ShiXieXuanNocedalGeneralMethod(absolute_precision, initial_step) ( f_prime_approx, number_of_function_evaluations, ) = method.compute_derivative(function, x) first_derivative_value = first_derivative(x) absolute_error = abs(f_prime_approx - first_derivative_value) print( "x = %.3f, error = %.3e, Func. eval. = %d" % (x, absolute_error, number_of_function_evaluations) ) .. rst-class:: sphx-glr-script-out .. code-block:: none DerivativeBenchmarkProblem name = exp x = 1.0 f(x) = 2.718281828459045 f'(x) = 2.718281828459045 f''(x) = 2.718281828459045 f^(3)(x) = 2.718281828459045 f^(4)(x) = 2.718281828459045 f^(5)(x) = 2.718281828459045 Exact h* = 4.797e-06 x = 1.000, error = 4.193e-10, Func. eval. = 63 .. GENERATED FROM PYTHON SOURCE LINES 134-136 Perform the benchmark --------------------- .. GENERATED FROM PYTHON SOURCE LINES 139-162 .. code-block:: Python print("+ Benchmark on several points") number_of_test_points = 21 # This number of test points is odd problem = nd.SinProblem() print(problem) interval = problem.get_interval() function = problem.get_function() first_derivative = problem.get_first_derivative() initial_step = 1.0e2 test_points = np.linspace(interval[0], interval[1], number_of_test_points) relative_precision = 1.0e-15 absolute_precision = abs(function(x)) * relative_precision method = ShiXieXuanNocedalGeneralMethod(absolute_precision, initial_step) average_relative_error, average_feval, data = nd.benchmark_method( function, first_derivative, test_points, method.compute_derivative, verbose=True, ) print("Average relative error =", average_relative_error) print("Average number of function evaluations =", average_feval) tabulate.tabulate(data, headers=["x", "Rel. err.", "F. Eval."], tablefmt="html") .. rst-class:: sphx-glr-script-out .. code-block:: none + Benchmark on several points DerivativeBenchmarkProblem name = sin x = 1.0 f(x) = 0.8414709848078965 f'(x) = 0.5403023058681398 f''(x) = -0.8414709848078965 f^(3)(x) = -0.5403023058681398 f^(4)(x) = 0.8414709848078965 f^(5)(x) = 0.5403023058681398 x = -3.142, abs. error = nan, rel. error = nan, Func. eval. = -1 x = -2.827, abs. error = 2.221e-11, rel. error = 2.335e-11, Func. eval. = 87 x = -2.513, abs. error = 3.156e-11, rel. error = 3.901e-11, Func. eval. = 93 x = -2.199, abs. error = 5.525e-11, rel. error = 9.399e-11, Func. eval. = 75 x = -1.885, abs. error = 2.995e-11, rel. error = 9.691e-11, Func. eval. = 75 x = -1.571, abs. error = 8.482e-17, rel. error = 1.385e+00, Func. eval. = 21 x = -1.257, abs. error = 2.762e-11, rel. error = 8.937e-11, Func. eval. = 75 x = -0.942, abs. error = 5.757e-11, rel. error = 9.795e-11, Func. eval. = 75 x = -0.628, abs. error = 3.814e-11, rel. error = 4.715e-11, Func. eval. = 93 x = -0.314, abs. error = 2.453e-11, rel. error = 2.580e-11, Func. eval. = 87 x = 0.000, abs. error = nan, rel. error = nan, Func. eval. = -1 x = 0.314, abs. error = 2.453e-11, rel. error = 2.580e-11, Func. eval. = 87 x = 0.628, abs. error = 3.814e-11, rel. error = 4.715e-11, Func. eval. = 93 x = 0.942, abs. error = 5.757e-11, rel. error = 9.795e-11, Func. eval. = 75 x = 1.257, abs. error = 2.762e-11, rel. error = 8.937e-11, Func. eval. = 75 x = 1.571, abs. error = 8.482e-17, rel. error = 1.385e+00, Func. eval. = 21 x = 1.885, abs. error = 2.995e-11, rel. error = 9.691e-11, Func. eval. = 75 x = 2.199, abs. error = 5.525e-11, rel. error = 9.399e-11, Func. eval. = 75 x = 2.513, abs. error = 3.156e-11, rel. error = 3.901e-11, Func. eval. = 93 x = 2.827, abs. error = 2.221e-11, rel. error = 2.335e-11, Func. eval. = 87 x = 3.142, abs. error = nan, rel. error = nan, Func. eval. = -1 Average relative error = nan Average number of function evaluations = 64.71428571428571 .. raw:: html
x Rel. err. F. Eval.
-3.14159 nan -1
-2.82743 2.33493e-11 87
-2.51327 3.90051e-11 93
-2.19911 9.39905e-11 75
-1.88496 9.69055e-11 75
-1.5708 1.38529 21
-1.25664 8.93713e-11 75
-0.942478 9.79518e-11 75
-0.628319 4.71452e-11 93
-0.314159 2.57974e-11 87
0 nan -1
0.314159 2.57974e-11 87
0.628319 4.71452e-11 93
0.942478 9.79518e-11 75
1.25664 8.93713e-11 75
1.5708 1.38529 21
1.88496 9.69055e-11 75
2.19911 9.39905e-11 75
2.51327 3.90051e-11 93
2.82743 2.33493e-11 87
3.14159 nan -1


.. GENERATED FROM PYTHON SOURCE LINES 163-176 Notice that the method does not perform correctly for the point :math:`x = 0` for the polynomial problem. This test point appears only if the number of test points is odd, because the test interval is symmetric with respect to :math:`x = 0`. For this problem, the method does not perform correctly because the value of the function is zero at :math:`x = 0`. The method can perform correctly in this case, if it is provided a consistent value of the absolute error of the function value. Here, we compute the absolute error depending on the relative error and the absolute value of the value of the function. If the value of the function is zero, then the computed absolute error is zero, which produces a failure of the method. .. GENERATED FROM PYTHON SOURCE LINES 178-179 Map from the problem name to the initial step. .. GENERATED FROM PYTHON SOURCE LINES 181-200 .. code-block:: Python initial_step_map = { "polynomial": 1.0, "inverse": 1.0e0, "exp": 1.0e-1, "log": 1.0e-3, # x > 0 "sqrt": 1.0e-3, # x > 0 "atan": 1.0e0, "sin": 1.0e0, "scaled exp": 1.0e5, "GMSW": 1.0e0, "SXXN1": 1.0e0, "SXXN2": 1.0e0, "SXXN3": 1.0e0, "SXXN4": 1.0e0, "Oliver1": 1.0e0, "Oliver2": 1.0e0, "Oliver3": 1.0e-3, } .. GENERATED FROM PYTHON SOURCE LINES 201-203 The next script evaluates a collection of benchmark problems using the :class:`~numericalderivative.ShiXieXuanNocedalGeneral` class. .. GENERATED FROM PYTHON SOURCE LINES 205-254 .. code-block:: Python number_of_test_points = 100 # This value can significantly change the results data = [] function_list = nd.build_benchmark() number_of_functions = len(function_list) average_absolute_error_list = [] average_feval_list = [] relative_precision = 1.0e-15 delta_x = 1.0e-9 for i in range(number_of_functions): problem = function_list[i] name = problem.get_name() initial_step = initial_step_map[name] function = problem.get_function() first_derivative = problem.get_first_derivative() interval = problem.get_interval() lower_x_bound, upper_x_bound = problem.get_interval() print(f"Function #{i}, {name}") if name == "sin": # Change the lower and upper bound so that the points +/-pi # are excluded (see below for details). lower_x_bound += delta_x upper_x_bound -= delta_x test_points = np.linspace(lower_x_bound, upper_x_bound, number_of_test_points) method = ShiXieXuanNocedalGeneralMethod(relative_precision, initial_step) average_relative_error, average_feval, _ = nd.benchmark_method( function, first_derivative, test_points, method.compute_derivative ) average_absolute_error_list.append(average_relative_error) average_feval_list.append(average_feval) data.append( ( name, average_relative_error, average_feval, ) ) data.append( [ "Average", np.nanmean(average_absolute_error_list), np.nanmean(average_feval_list), ] ) tabulate.tabulate( data, headers=["Name", "Average rel. error", "Average func. eval"], tablefmt="html", ) .. rst-class:: sphx-glr-script-out .. code-block:: none Function #0, polynomial Function #1, inverse Function #2, exp Function #3, log Function #4, sqrt Function #5, atan Function #6, sin Function #7, scaled exp Function #8, GMSW Function #9, SXXN1 Function #10, SXXN2 Function #11, SXXN3 Function #12, SXXN4 Function #13, Oliver1 Function #14, Oliver2 Function #15, Oliver3 .. raw:: html
Name Average rel. error Average func. eval
polynomial nan 30.86
inverse 1.09323e-10 60.24
exp 5.59359e-11 63
log 1.00322e-10 28.62
sqrt 7.86586e-11 24.84
atan 3.98083e-10 56.16
sin 9.23643e-11 63.72
scaled exp 4.95143e-11 63
GMSW 4.03997e-11 69.24
SXXN1 7.49722e-09 63.36
SXXN2 nan 98.16
SXXN3 4.50964e-11 59.4
SXXN4 3.71608e-11 60.18
Oliver1 3.90019e-11 63
Oliver2 1.36955e-10 74.22
Oliver3 4.39756e-11 29.34
Average 6.23144e-10 56.7088


.. GENERATED FROM PYTHON SOURCE LINES 255-265 Notice that the method cannot perform correctly for the sin function at the point :math:`x = \pm \pi`. Indeed, this function is such that :math:`f(x) = 0`. In this case, the absolute error is zero if it is computed from the relative error. Therefore, we make so that the points :math:`\pm \pi` are excluded from the benchmark. The same problem appears at the point :math:`x = 0`. This point is not included in the test set if the number of points is even (e.g. with `number_of_test_points = 100`), but it might appear if the number of test points is odd. .. GENERATED FROM PYTHON SOURCE LINES 267-270 Notice that the method cannot perform correctly for the polynomial problem because the third derivative is zero. This produces a zero test ratio which makes the method to fail. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.245 seconds) .. _sphx_glr_download_auto_example_plot_shi_xie_xuan_nocedal_general_benchmark.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_shi_xie_xuan_nocedal_general_benchmark.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_shi_xie_xuan_nocedal_general_benchmark.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_shi_xie_xuan_nocedal_general_benchmark.zip `