Prev Next atomic_four_dynamic.cpp

@(@\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 Functions with Dynamic Parameters: Example and Test

Purpose
This example demonstrates using dynamic parameters with an atomic_four function.

Function
For this example, the atomic function @(@ g : \B{R}^3 \rightarrow \B{R}^3 @)@ is defined by @(@ g_0 (x) = x_0 * x_ 0 @)@, @(@ g_1 (x) = x_0 * x_ 1 @)@, @(@ g_2 (x) = x_1 * x_ 2 @)@.

Define Atomic Function

// empty namespace
namespace {
    // atomic_dynamic
    class atomic_dynamic : public CppAD::atomic_four<double> {
    public:
        atomic_dynamic(const std::string& name) :
        CppAD::atomic_four<double>(name)
        { }
    private:
        // for_type
        bool for_type(
        size_t                                     call_id     ,
        const CppAD::vector<CppAD::ad_type_enum>&  type_x      ,
        CppAD::vector<CppAD::ad_type_enum>&        type_y      ) override
        {   assert( call_id == 0 );       // default value
            assert( type_x.size() == 3 ); // n
            assert( type_y.size() == 3 ); // m
            //
            // type_y
            type_y[0] = type_x[0];
            type_y[1] = std::max( type_x[0], type_x[1] );
            type_y[2] = std::max( type_x[1], type_x[2] );
            return true;
        }
        // forward
        bool forward(
            size_t                        call_id      ,
            const CppAD::vector<bool>&    select_y     ,
            size_t                        order_low    ,
            size_t                        order_up     ,
            const CppAD::vector<double>&  taylor_x     ,
            CppAD::vector<double>&        taylor_y     ) override
        {
# ifndef NDEBUG
            size_t q = order_up + 1;
            size_t n = taylor_x.size() / q;
            size_t m = taylor_y.size() / q;
            assert( n == 3 );
            assert( m == 3 );
# endif
            // ok
            bool ok = order_low == 0 && order_up == 0;
            if( ! ok )
                return ok;
            //
            // taylor_y[0] = g_0 = x_0 * x_0
            if( select_y[0] )
                taylor_y[0] = taylor_x[0] * taylor_x[0];
            //
            // taylor_y[1] = g_1 = x_0 * x_1
            if( select_y[1] )
                taylor_y[1] = taylor_x[0] * taylor_x[1];
            //
            // taylor_y[2] = g_2 = x_1 * x_2
            if( select_y[2] )
                taylor_y[2] = taylor_x[1] * taylor_x[2];
            //
            return ok;
        }
    };
}

Use Atomic Function

bool dynamic(void)
{   // ok, eps
    bool ok = true;
    double eps = 10. * CppAD::numeric_limits<double>::epsilon();
    //
    // afun
    atomic_dynamic afun("atomic_dynamic");
    //
    // c, p, u
    CPPAD_TESTVECTOR(double) c(1), p(1), u(1);
    c[0] = 2.0;
    p[0] = 3.0;
    u[0] = 4.0;
    //
    //
    // np, nu, ny
    size_t np = 1;
    size_t nu = 1;
    size_t nx = 3;
    size_t ny = 3;
    //
    // ap
    // indepndent dynamic parameter vector
    CPPAD_TESTVECTOR( CppAD::AD<double> ) ap(np);
    ap[0] = p[0];
    //
    // au
    // independent variable vector
    CPPAD_TESTVECTOR( CppAD::AD<double> ) au(nu);
    au[0] = u[0];
    //
    // Independent
    CppAD::Independent(au, ap);
    //
    // ay
    // y = ( c * c, c * p, p * x )
    CPPAD_TESTVECTOR( CppAD::AD<double> ) ax(nx), ay(ny);
    ax[0] = c[0];  // x_0
    ax[1] = ap[0]; // x_1
    ax[2] = au[0]; // x_2
    afun(ax, ay);
    //
    // ay
    // check type of result
    ok &= Constant( ay[0] );
    ok &= Dynamic(  ay[1] );
    ok &= Variable( ay[2] );
    //
    // f
    // f(u) = (c * c, c * p, p * u)
    CppAD::ADFun<double> f;
    f.Dependent (au, ay);
    //
    // ay[0]
    double check = c[0] * c[0];
    ok &= CppAD::NearEqual( Value(ay[0]) , check,  eps, eps);
    //
    // ay[1]
    check = c[0] * p[0];
    ok &= CppAD::NearEqual( Value(ay[1]) , check,  eps, eps);
    //
    // ay[2]
    check = p[0] * u[0];
    ok &= CppAD::NearEqual( Value(ay[2]) , check,  eps, eps);
    //
    // y = f.Foward(0, u)
    CPPAD_TESTVECTOR(double) y(ny);
    y     = f.Forward(0, u);
    check = c[0] * c[0];
    ok    &= CppAD::NearEqual(y[0] , check,  eps, eps);
    check = c[0] * p[0];
    ok    &= CppAD::NearEqual(y[1] , check,  eps, eps);
    check = p[0] * u[0];
    ok    &= CppAD::NearEqual(y[2] , check,  eps, eps);
    //
    // p
    p[0]   = 2.0 * p[0];
    f.new_dynamic(p);
    //
    // y = f.Foward(0, u)
    y     = f.Forward(0, u);
    check = c[0] * c[0];
    ok    &= CppAD::NearEqual(y[0] , check,  eps, eps);
    check = c[0] * p[0];
    ok    &= CppAD::NearEqual(y[1] , check,  eps, eps);
    check = p[0] * u[0];
    ok    &= CppAD::NearEqual(y[2] , check,  eps, eps);
    //
    return ok;
}

Input File: example/atomic_four/dynamic.cpp