Numerical differentiation (qcip_tools.numerical_differentiation
)
Mathematical background
Numerical derivation
Theory
This an application of the Neville’s algorithm.
Let
where
Given a small value
where
Therefore,
An estimate of an
where
Let’s assume that one can determine
In order for the equality to be satisfied, it is necessary that:
This defines a set of
Type |
||
---|---|---|
Forward ( |
0 |
|
Backward ( |
0 |
|
Centered ( |
Note that
The system of linear equation given by Eq. (2) is solved. Once the
It can be simply showed that the coefficients for a multivariate function is a tensor product of the coefficients for the univariates approximations. In this case
Note
In pratice, it wouldn’t change anything if a Taylor series (not centered at
Warning
If values of
Implementation
The ak_shifted()
in the python code.
In the code, to works with the romberg triangles defined below,
The Coefficients
class takes care of the computation of the different coefficients, storing them in Coefficients.mat_coefs
.
The Coefficients.prefactor()
function.
The compute_derivative_of_function(c, scalar_function, k, h0, input_space_dimension, **kwargs)
function does the whole computation (for uni and multivariate functions) and gives scalar_function(fields, h_0, **kwargs)
function must be defined, which must return the value of the Maclaurin expansion fields
(the **kwargs
if any.
c
is a list of tuple (Coefficient, int)
, which define the derivatives to compute and with respect to which coordinates (starting by 0) the differentiation must be performed.
For example, given
first_order = numerical_differentiation.Coefficients(1, 2, ratio=a, method='C')
second_order = numerical_differentiation.Coefficients(2, 2, ratio=a, method='C')
derivative_values = []
# compute d^3 E(x) / dx0 dx1^2
derivative_values.append(numerical_differentiation.compute_derivative_of_function(
[(first_order, 0), (second_order, 1)],
E, # assume defined
0, # k = 0
0.001, # h0
3 # input space is R³.
))
Warning
In the code, scalar_function()
receives the
Romberg’s scheme (Richardson extrapolation)
Theory
In quantum chemistry, the Richardson extrapolation is also known as the Romberg differentiation scheme. Like its integration counterpart, it allows to refine the value of a numerical derivatives by computing multiple estimate of the derivates.
Given Eq. (1) and a small
It is therefore possible to remove the
Let
where
A romberg triangle is obtained, with the following shape:
k= | h= | m=0 m=1 m=2 ...
----+-------+-----------------------------
0 | a⁰*h0 | val01 val11 val20 ...
1 | a¹*h0 | val02 val12 ...
2 | a²*h0 | val03 ...
... | ... | ...
If the minimal value
where
This “best” value is chosen according to the following flowchart:

Flowchart to select the “best” value in a Romberg triangle, adapted from the text in M. de Wergifosse et al. Int. J. Quant. Chem. 114, 900 (2014).
Note that the original paper does not give advices on what the threshold value should be, but it clearly depends on the order of magnitude of
Note
In the case where
Implementation
The RombergTriangle
class implement the Romberg’s triangle algorithm. The constructors expect the value corresponding to increasing k
values to be passed as argument.
The RombergTriangle.romberg_triangle[k, m]
. Note that the values for which
The find_best_value()
implement the flowchart showed above. To help the (eventual) debugging and understanding, a verbose
option is available.
For example, for an univariate function
a = 2.0
# Forward first order derivative:
c = numerical_differentiation.Coefficients(1, 1, ratio=a, method='F')
derivative_values = []
# compute dF(x) / dx
for k in range(5):
derivative_values.append(numerical_differentiation.compute_derivative_of_function(
[(c, 0)], # derivative with respect to the first (and only) variable
univariate_function, # assume defined
k,
0.001, # f0
1 # R → R
))
t = numerical_differentiation.RombergTriangle(derivative_values, ratio=a)
position, value, iteration_error = t.find_best_value(threshold=1e-5, verbose=True)
For a bivariate function
a = 2.0
# centered first and second order derivative:
c1 = numerical_differentiation.Coefficients(1, 2, ratio=a, method='C')
c2 = numerical_differentiation.Coefficients(2, 2, ratio=a, method='C')
derivative_values = []
# compute d³F(x,y) / dxdy²
for k in range(5):
derivative_values.append(numerical_differentiation.compute_derivative_of_function(
[(c1, 0), (c2, 1)], # first and second order derivative with respect to the first and second variable
bivariate_function, # assume defined
k,
0.001, # f0
2 # R² → R
))
t = numerical_differentiation.RombergTriangle(derivative_values, ratio=a, r=2) # r=2 because centered
position, value, iteration_error = t.find_best_value()
Sources
D. Eberly, « Derivative Approximation by Finite Difference ». From the Geometric Tools documentation (last consultation: March 4, 2017).
J.N. Lyness et al. Numer. Math. 8, 458 (1966).
L.F. Richardson et al. Philosophical Transactions of the Royal Society of London. Series A, Containing Papers of a Mathematical or Physical Character 226, 299 (1927).
M. de Wergifosse et al. Int. J. Quant. Chem. 114, 900 (2014).
A.A.K. Mohammed et al. J. Comp. Chem. 34, 1497 (2013).
API documentation
- class qcip_tools.numerical_differentiation.Coefficients(d, p, ratio=2.0, method='C')
Class to store the coefficients for the derivative calculation.
- Parameters:
d (int) – derivation order
p (int) – order of error
ratio (float) – ratio (a)
method (str) – derivation method, either forward (F), backward (B) or centered (C)
- static choose_p_for_centered(d, shift=0)
Choose the precision so that
is even (for centered derivatives)- Parameters:
d (int) – order of the derivative
shift (int) – increase the precision
- prefactor(k, h0)
return the
prefactor, with .- Parameters:
h0 (float) – minimal value
k (int) – Minimal amplitude
- Returns:
prefactor
- Return type:
float
- class qcip_tools.numerical_differentiation.RombergTriangle(values, ratio=2.0, r=1, force_choice=None)
Do a Romberg triangle to lower (remove) the influence of higher-order derivatives.
Note: Romberg triangle indices are n, then k (but printing require n to be column, so invert them !)
- Parameters:
vals (list) – list of derivatives, the first one calculated with the lowest k, the last one the larger
ratio (float) – ratio (a)
r (int) – derivatives to remove. r=1 for backward and forward approximation and 2 for centered approximation.
force_choice (tuple) – force the choice in the Romberg triangle, must be a tuple of the form
(k, m)
- amplitude_error(k=0, m=0)
Compute
- Parameters:
k (int) – amplitude
m (int) – iteration
- Return type:
float
- find_best_value(threshold=1e-05, verbose=False, out=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>)
Find the “best value” in the Romberg triangle
- Parameters:
threshold (float) – threshold for maximum iteration error
verbose (bool) – get an insight of how the value was chosen
- Returns:
a tuple of 3 information: position (tuple), value (float), iteration error (float)
- Return type:
tuple
- iteration_error(m=0, k=0)
Compute
- Parameters:
k (int) – amplitude
m (int) – iteration
- Return type:
float
- romberg_triangle_repr(with_decoration=False, k_min=0)
Print the Romberg triangle …
- qcip_tools.numerical_differentiation.ak_shifted(ratio, q)
Match the
and the real value.For a given
, returns- Parameters:
q (int) – q
ratio (float) – ratio (a)
- Return type:
float
- qcip_tools.numerical_differentiation.compute_derivative_of_function(c, scalar_function, k, h0, input_space_dimension=1, **kwargs)
Compute the numerical derivative of a scalar, calling the appropriate results through
scalar_function
, to which the**kwargs
parameter is provided.- Parameters:
c (list) – list of tuple to describe the numerical derivative (Coefficient, coordinate)
scalar_function (callback) – a callback function to access the different quantities
k (int) – minimal amplitude
h0 (float) – minimal value
input_space_dimension (int) – dimension of the input vector space
kwargs (dict) – other arguments, transfered to
scalar_function()
- Returns:
value of the derivative (as a scalar)
- Return type:
float
- qcip_tools.numerical_differentiation.real_fields(fields, min_field, ratio)
Return the “real value” of the field applied
- Parameters:
fields (list) – input field (in term of ak)
min_field (float) – minimal field
ratio (float) – ratio
- Return type:
list