Derivative Library Tutorial
Wang Feng
March 18, 2014
1 Headers, Namespace and Compilation
The header file for derivative is
#include <derivative/derivative.hpp>
The header file for second derivative is
#include <derivative/second derivative.hpp>
The namespace of derivative is
using namespace numeric;
A typical commandline compilation is
g++ -o test test.cc -std=c++11 -O2 -IPATH/TO/HEAD/FILE
2 Derivative
2.1 derivatives of normal functions
To calculate the derivative of a simple function f(x, y) = sin x cos y, we first need to define
the function in c++ code:
double fxy ( double x, double y )
{
return std::sin( x ) * std::cos( y );
}
then generate the
f (x,y)
x
using
auto const& dfx = numeric::make derivative<0>( fxy );
and
f (x,y)
y
using
auto const& dfy = numeric::make derivative<1>( fxy );
to evaluate
f (x,y)
x
(1,2)
, we simply call dfx as a normal c++ function
std::cout << ”df / dx at ( 1, 2 ) is << dfx( 1, 2 ) << \n;
also, to evaluate
f (x,y)
y
(1,2)
std::cout << ”df / dy at ( 1, 2 ) is << dfy( 1, 2 ) << \n;
2.2 derivatives of functions that receive a pointer as argument
Same function as in the previous subsection, but we make some modification to make it
receive only one pointer:
double fxy( double* x )
{
return std::sin(x[0]) * std::cos(x[1]);
}
then define the derivatives:
auto const& dfdx = numeric::make derivative( fxy, 0 );
auto const& dfdy = numeric::make derivative( fxy, 1 );
to evaluate them at the point(1,2), we make an array x[], then call them as normal c
functions:
double x[] = { 1.0, 2.0 };
std::cout << \ndf/dx at (1.0, 2.0) is << dfdx(x) << \n;
std::cout << \ndf/dy at (1.0, 2.0) is << dfdy(x) << \n;
2.3 more than functions
Our derivative can also deal with functors, lambda objects etc., here is an example with a
functor:
#include <derivative/derivative.hpp>
#include <iostream>
#include <cmath>
struct sfxy
{
double a;
sfxy( double a = 2.0 ) : a(a ) {}
double operator()( double* x ) const
{
return a * std::sin(x[0]) * std::cos(x[1]);
}
};
int main()
{
sfxy const fxy( 5.0 );
auto const& dfdx = numeric::make derivative( fxy, 0 );
auto const& dfdy = numeric::make derivative( fxy, 1 );
double x[] = { 1.0, 2.0 };
std::cout << \ndf/dx at (1.0, 2.0) is << dfdx(x) << \n;
std::cout << \ndf/dy at (1.0, 2.0) is << dfdy(x) << \n;
return 0;
}
3 Second Derivaitve
The code creating the second derivative objects is very similar to the code creating the first
derivatives, but with one more parameter.
Second derivatives for a normal c function:
double fxyz( double x, double y, double z )
{
return std::sin(std::pow( x, y ) * z);
}
void fxyz test()
{
auto const& fxyz 00 = numeric::make second derivative<0,0>( fxyz );
auto const& fxyz 01 = numeric::make second derivative<0,1>( fxyz );
auto const& fxyz 02 = numeric::make second derivative<0,2>( fxyz );
auto const& fxyz 10 = numeric::make second derivative<1,0>( fxyz );
auto const& fxyz 11 = numeric::make second derivative<1,1>( fxyz );
auto const& fxyz 12 = numeric::make second derivative<1,2>( fxyz );
auto const& fxyz 20 = numeric::make second derivative<2,0>( fxyz );
auto const& fxyz 21 = numeric::make second derivative<2,1>( fxyz );
auto const& fxyz 22 = numeric::make second derivative<2,2>( fxyz );
std::cout << \nfxyz 00 at(1.0, 2.0, 3.0) is << fxyz 00( 1.0, 2.0, 3.0 ) << \n;
std::cout << \nfxyz 01 at(1.0, 2.0, 3.0) is << fxyz 01( 1.0, 2.0, 3.0 ) << \n;
std::cout << \nfxyz 02 at(1.0, 2.0, 3.0) is << fxyz 02( 1.0, 2.0, 3.0 ) << \n;
std::cout << \nfxyz 10 at(1.0, 2.0, 3.0) is << fxyz 10( 1.0, 2.0, 3.0 ) << \n;
std::cout << \nfxyz 11 at(1.0, 2.0, 3.0) is << fxyz 11( 1.0, 2.0, 3.0 ) << \n;
std::cout << \nfxyz 12 at(1.0, 2.0, 3.0) is << fxyz 12( 1.0, 2.0, 3.0 ) << \n;
std::cout << \nfxyz 20 at(1.0, 2.0, 3.0) is << fxyz 20( 1.0, 2.0, 3.0 ) << \n;
std::cout << \nfxyz 21 at(1.0, 2.0, 3.0) is << fxyz 21( 1.0, 2.0, 3.0 ) << \n;
std::cout << \nfxyz 22 at(1.0, 2.0, 3.0) is << fxyz 22( 1.0, 2.0, 3.0 ) << \n;
}
And for a function receiving a pointer as parameter:
double gxyz( double* x )
{
return std::sin(std::pow( x[0], x[1] ) * x[2] );
}
void gxyz test()
{
auto const& gxyz 00 = numeric::make second derivative( gxyz, 0, 0 );
auto const& gxyz 01 = numeric::make second derivative( gxyz, 0, 1 );
auto const& gxyz 02 = numeric::make second derivative( gxyz, 0, 2 );
auto const& gxyz 10 = numeric::make second derivative( gxyz, 1, 0 );
auto const& gxyz 11 = numeric::make second derivative( gxyz, 1, 1 );
auto const& gxyz 12 = numeric::make second derivative( gxyz, 1, 2 );
auto const& gxyz 20 = numeric::make second derivative( gxyz, 2, 0 );
auto const& gxyz 21 = numeric::make second derivative( gxyz, 2, 1 );
auto const& gxyz 22 = numeric::make second derivative( gxyz, 2, 2 );
double x[] = { 1.0, 2.0, 3.0 };
std::cout << \ngxyz 00 at(1.0, 2.0, 3.0) is << gxyz 00( x ) << \n;
std::cout << \ngxyz 01 at(1.0, 2.0, 3.0) is << gxyz 01( x ) << \n;
std::cout << \ngxyz 02 at(1.0, 2.0, 3.0) is << gxyz 02( x ) << \n;
std::cout << \ngxyz 10 at(1.0, 2.0, 3.0) is << gxyz 10( x ) << \n;
std::cout << \ngxyz 11 at(1.0, 2.0, 3.0) is << gxyz 11( x ) << \n;
std::cout << \ngxyz 12 at(1.0, 2.0, 3.0) is << gxyz 12( x ) << \n;
std::cout << \ngxyz 20 at(1.0, 2.0, 3.0) is << gxyz 20( x ) << \n;
std::cout << \ngxyz 21 at(1.0, 2.0, 3.0) is << gxyz 21( x ) << \n;
std::cout << \ngxyz 22 at(1.0, 2.0, 3.0) is << gxyz 22( x ) << \n;
}