Prev Next atomic_four_forward

@(@\newcommand{\W}[1]{ \; #1 \; } \newcommand{\R}[1]{ {\rm #1} } \newcommand{\B}[1]{ {\bf #1} } \newcommand{\D}[2]{ \frac{\partial #1}{\partial #2} } \newcommand{\DD}[3]{ \frac{\partial^2 #1}{\partial #2 \partial #3} } \newcommand{\Dpow}[2]{ \frac{\partial^{#1}}{\partial {#2}^{#1}} } \newcommand{\dpow}[2]{ \frac{ {\rm d}^{#1}}{{\rm d}\, {#2}^{#1}} }@)@This is cppad-20221105 documentation. Here is a link to its current documentation .
Atomic Function Forward Mode

Syntax

Base
ok = afun.forward(
    
call_idselect_y,
    
order_loworder_uptype_xtaylor_xtaylor_y
)


AD<Base>
ok = afun.forward(
    
call_idselect_y,
    
order_loworder_uptype_xataylor_xataylor_y
)


Prototype

Base

template <class Base>
bool atomic_four<Base>::forward(
    size_t                       call_id     ,
    const vector<bool>&          select_y    ,
    size_t                       order_low   ,
    size_t                       order_up    ,
    const vector<Base>&          taylor_x    ,
    vector<Base>&                taylor_y    )

AD<Base>

template <class Base>
bool atomic_four<Base>::forward(
    size_t                       call_id      ,
    const vector<bool>&          select_y    ,
    size_t                       order_low    ,
    size_t                       order_up     ,
    const vector< AD<Base> >&    ataylor_x    ,
    vector< AD<Base> >&          ataylor_y    )

Base
see Base .

vector
is the CppAD_vector template class.

Usage

Base
The Base syntax and prototype are used by a call to the atomic function afun . They are also used by f.Forward and f.new_dynamic where f has prototype
    ADFun<
Basef
and afun is used during the recording of f .

AD<Base>
The AD<Base> syntax and prototype are used by af.Forward and af.new_dynamic where af has prototype
    ADFun< AD<
Base> , Base > af
and afun is used in a function af , created from f using base2ad .

Implementation
The taylor_x , taylor_y version of this function must be defined by the atomic_user class. It can return ok == false (and not compute anything) for values of order_up that are greater than those used by your forward mode calculations. Order zero must be implemented.

call_id
See call_id .

select_y
This argument has size equal to the number of results to this atomic function; i.e. the size of ay . It specifies which components of y the corresponding Taylor coefficients must be computed.

order_low
This argument specifies the lowest order Taylor coefficient that we are computing.

p
We sometimes use the notation p = order_low below.

order_up
This argument is the highest order Taylor coefficient that we are computing ( order_low <= order_up ).

q
We use the notation q = order_up + 1 below. This is the number of Taylor coefficients for each component of x and y .

taylor_x
The size of taylor_x is q*n . For @(@ j = 0 , \ldots , n-1 @)@ and @(@ k = 0 , \ldots , q-1 @)@, we use the Taylor coefficient notation @[@ \begin{array}{rcl} x_j^k & = & \R{taylor\_x} [ j * q + k ] \\ X_j (t) & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^{q-1} t^{q-1} \end{array} @]@ Note that superscripts represent an index for @(@ x_j^k @)@ and an exponent for @(@ t^k @)@. Also note that the Taylor coefficients for @(@ X(t) @)@ correspond to the derivatives of @(@ X(t) @)@ at @(@ t = 0 @)@ in the following way: @[@ x_j^k = \frac{1}{ k ! } X_j^{(k)} (0) @]@

parameters
If the j-th component of x is a parameter,
    
type_x[j] < CppAD::variable_enum
In this case, for k > 0 ,
    
taylor_xj * q + k ] == 0

ataylor_x
The specifications for ataylor_x is the same as for taylor_x (only the type of ataylor_x is different).

taylor_y
The size of taylor_y is q*m . Upon return, For @(@ i = 0 , \ldots , m-1 @)@ and @(@ k = 0 , \ldots , q-1 @)@, if select_y[i] is true, @[@ \begin{array}{rcl} Y_i (t) & = & g_i [ X(t) ] \\ Y_i (t) & = & y_i^0 + y_i^1 t^1 + \cdots + y_i^{q-1} t^{q-1} + o( t^{q-1} ) \\ \R{taylor\_y} [ i * q + k ] & = & y_i^k \end{array} @]@ where @(@ o( t^{q-1} ) / t^{q-1} \rightarrow 0 @)@ as @(@ t \rightarrow 0 @)@. Note that superscripts represent an index for @(@ y_j^k @)@ and an exponent for @(@ t^k @)@. Also note that the Taylor coefficients for @(@ Y(t) @)@ correspond to the derivatives of @(@ Y(t) @)@ at @(@ t = 0 @)@ in the following way: @[@ y_j^k = \frac{1}{ k ! } Y_j^{(k)} (0) @]@ If @(@ p > 0 @)@, for @(@ i = 0 , \ldots , m-1 @)@ and @(@ k = 0 , \ldots , p-1 @)@, the input of taylor_y satisfies @[@ \R{taylor\_y} [ i * q + k ] = y_i^k @]@ These values do not need to be recalculated and can be used during the computation of the higher order coefficients.

ataylor_y
The specifications for ataylor_y is the same as for taylor_y (only the type of ataylor_y is different).

ok
If this calculation succeeded, ok is true. Otherwise, it is false.

Discussion
For example, suppose that order_up == 2 , and you know how to compute the function @(@ g(x) @)@, its first derivative @(@ g^{(1)} (x) @)@, and it component wise Hessian @(@ g_i^{(2)} (x) @)@. Then you can compute taylor_x using the following formulas: @[@ \begin{array}{rcl} y_i^0 & = & Y(0) = g_i ( x^0 ) \\ y_i^1 & = & Y^{(1)} ( 0 ) = g_i^{(1)} ( x^0 ) X^{(1)} ( 0 ) = g_i^{(1)} ( x^0 ) x^1 \\ y_i^2 & = & \frac{1}{2 !} Y^{(2)} (0) \\ & = & \frac{1}{2} X^{(1)} (0)^\R{T} g_i^{(2)} ( x^0 ) X^{(1)} ( 0 ) + \frac{1}{2} g_i^{(1)} ( x^0 ) X^{(2)} ( 0 ) \\ & = & \frac{1}{2} (x^1)^\R{T} g_i^{(2)} ( x^0 ) x^1 + g_i^{(1)} ( x^0 ) x^2 \end{array} @]@ For @(@ i = 0 , \ldots , m-1 @)@, and @(@ k = 0 , 1 , 2 @)@, @[@ \R{taylor\_y} [ i * q + k ] = y_i^k @]@

Example
The following is an example forward definition taken from atomic_four_norm_sq.cpp :
        bool forward(
            size_t                             call_id     ,
            const CppAD::vector<bool>&         select_y    ,
            size_t                             order_low   ,
            size_t                             order_up    ,
            const CppAD::vector<double>&       tx          ,
            CppAD::vector<double>&             ty          ) override
        {
            size_t q = order_up + 1;
            size_t n = tx.size() / q;
    # ifndef NDEBUG
            size_t m = ty.size() / q;
            assert( call_id == 0 );
            assert( m == 1 );
            assert( m == select_y.size() );
    # endif
            // ok
            bool ok = order_up <= 1 && order_low <= order_up;
            if ( ! ok )
                return ok;
            //
            // sum = x_0^0 * x_0^0 + x_1^0 * x_1^0 + ...
            double sum = 0.0;
            for(size_t j = 0; j < n; ++j)
            {   double xj0 = tx[ j * q + 0];
                sum       += xj0 * xj0;
            }
            //
            // ty[0] = sum
            if( order_low <= 0 )
                ty[0] = sum;
            if( order_up < 1 )
                return ok;

            // sum = x_0^0 * x_0^1 + x_1^0 ^ x_1^1 + ...
            sum   = 0.0;
            for(size_t j = 0; j < n; ++j)
            {   double xj0 = tx[ j * q + 0];
                double xj1 = tx[ j * q + 1];
                sum       += xj0 * xj1;
            }
            // ty[1] = 2.0 * sum
            assert( order_up == 1 );
            ty[1] = 2.0 * sum;
            return ok;

            // Assume we are not using forward mode with order > 1
            assert( ! ok );
            return ok;
        }        

Input File: include/cppad/core/atomic/four/forward.hpp