The version of the Function Parser library that ships with MOOSE contains an automatic differentiation feature that is not present in the upstream version.

Include the automatic differentiation module (which also adds just in time compilation support) with

#include "libmesh/fparser_ad.hh"

The module provides the class

FunctionParserADBase<Real>

which derives from

FunctionParserBase<Real>

and provides the additional method

int AutoDiff(const std::string& var);

where var is the name of the variable to take the derivative with respect to. The AutoDiff method must be called on an initialized and parsed (but not optimized) Function Parser object.

The automatic differentiation system transforms the compiled bytecode of the parsed function into the bytecode of the derivative. The AutoDiff method can be called multiple times to generate high order derivatives.

The helper method

bool isZero();

can be called after optimizing the Function Parser object to check if the function is a constant zero (i.e. the bytecode consists only of a push 0 command).

Limitations

Almost all FParser opcodes are supported, except PCall and FCall, which are function calls to other FParser objects and calls to custom functions.

The automatic differentiation will currently complain when taking derivatives of functions that are not differentiable in a countable infinite number of points (such as int()), it will however take derivatives of functions like the absolute value abs() that are not differentiable in only a single point. This limitation is arbitrary and may be changed in future versions.

The current version of the AD module does support differentiationg FParser objects that have been previously optimized.

Example

The following code snippet illustrates how to compute and evaluate a derivative:

FunctionParserADBase<Real> fparser;
std::string func = "sin(a*x)+x^2*(3+sin(3*x))+a";

// Parse the input expression into bytecode
fparser.Parse(func, "x,a");

// transform F -> dF/dx
fparser.AutoDiff("x");

// run optimizer to simplify the derivative
fparser.Optimize();

// evaluate the derivative (method from FParserBase<Real>)
Real params[2] = {0.1, 1.7};
std::cout << fparser.Eval(params) << std::endl;

// print byte code of the derivative (needs debugging enabled)
fparser.PrintByteCode(std::cout);

Not that optimizing the FParser object using .Optimize() after taking the derivative is highly recommended, as the automatic differentiation generates lots of trivial terms. For example the derivative of 2*x is 0*x+2*1, which will be optimized to 2.

See also