Prev Next

@(@\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 .
Enable use of AD<Base> where Base is Adolc's adouble Type

Syntax
# include <cppad/example/base_adolc.hpp>

Example
The file mul_level_adolc.cpp contains an example use of Adolc's adouble type for a CppAD Base type. The file mul_level_adolc_ode.cpp contains a more realistic (and complex) example.

Include Files
This file base_adolc.hpp requires adouble to be defined. In addition, it is included before <cppad/cppad.hpp>, but it needs to include parts of CppAD that are used by this file. This is done with the following include commands:

# include <adolc/adolc.h>
# include <cppad/base_require.hpp>

CondExpOp
The type adouble supports a conditional assignment function with the syntax
    condassign(
abcd)
which evaluates to
    
a = (b > 0) ? c : d;
This enables one to include conditionals in the recording of adouble operations and later evaluation for different values of the independent variables (in the same spirit as the CppAD CondExp function).
namespace CppAD {
    inline adouble CondExpOp(
        enum  CppAD::CompareOp     cop ,
        const adouble            &left ,
        const adouble           &right ,
        const adouble        &trueCase ,
        const adouble       &falseCase )
    {   adouble result;
        switch( cop )
        {
            case CompareLt: // left < right
            condassign(result, right - left, trueCase, falseCase);
            break;

            case CompareLe: // left <= right
            condassign(result, left - right, falseCase, trueCase);
            break;

            case CompareEq: // left == right
            condassign(result, left - right, falseCase, trueCase);
            condassign(result, right - left, falseCase, result);
            break;

            case CompareGe: // left >= right
            condassign(result, right - left, falseCase, trueCase);
            break;

            case CompareGt: // left > right
            condassign(result, left - right, trueCase, falseCase);
            break;
            default:
            CppAD::ErrorHandler::Call(
                true     , __LINE__ , __FILE__ ,
                "CppAD::CondExp",
                "Error: for unknown reason."
            );
            result = trueCase;
        }
        return result;
    }
}

CondExpRel
The CPPAD_COND_EXP_REL macro invocation

namespace CppAD {
    CPPAD_COND_EXP_REL(adouble)
}

EqualOpSeq
The Adolc user interface does not specify a way to determine if two adouble variables correspond to the same operations sequence. Make EqualOpSeq an error if it gets used:
namespace CppAD {
    inline bool EqualOpSeq(const adouble &x, const adouble &y)
    {   CppAD::ErrorHandler::Call(
            true     , __LINE__ , __FILE__ ,
            "CppAD::EqualOpSeq(x, y)",
            "Error: adouble does not support EqualOpSeq."
        );
        return false;
    }
}

Identical
The Adolc user interface does not specify a way to determine if an adouble depends on the independent variables. To be safe (but slow) return false in all the cases below.
namespace CppAD {
    inline bool IdenticalCon(const adouble &x)
    {   return false; }
    inline bool IdenticalZero(const adouble &x)
    {   return false; }
    inline bool IdenticalOne(const adouble &x)
    {   return false; }
    inline bool IdenticalEqualCon(const adouble &x, const adouble &y)
    {   return false; }
}

Integer

    inline int Integer(const adouble &x)
    {    return static_cast<int>( x.getValue() ); }

azmul

namespace CppAD {
    CPPAD_AZMUL( adouble )
}

Ordered
namespace CppAD {
    inline bool GreaterThanZero(const adouble &x)
    {    return (x > 0); }
    inline bool GreaterThanOrZero(const adouble &x)
    {    return (x >= 0); }
    inline bool LessThanZero(const adouble &x)
    {    return (x < 0); }
    inline bool LessThanOrZero(const adouble &x)
    {    return (x <= 0); }
    inline bool abs_geq(const adouble& x, const adouble& y)
    {   return fabs(x) >= fabs(y); }
}

Unary Standard Math
The following required functions are defined by the Adolc package for the adouble base case:
acos, acosh, asin, asinh, atan, atanh, cos, cosh, erf, exp, fabs, log, sin, sinh, sqrt, tan.

erfc
If you provide --enable-atrig-erf on the configure command line, the adolc package supports all the c++11 math functions except erfc, expm1, and log1p. For the reason, we make using erfc an error:
namespace CppAD {
# define CPPAD_BASE_ADOLC_NO_SUPPORT(fun)                         \
    inline adouble fun(const adouble& x)                          \
    {   CPPAD_ASSERT_KNOWN(                                       \
            false,                                                \
            #fun ": adolc does not support this function"         \
        );                                                        \
        return 0.0;                                               \
    }
    CPPAD_BASE_ADOLC_NO_SUPPORT(erfc)
    CPPAD_BASE_ADOLC_NO_SUPPORT(expm1)
    CPPAD_BASE_ADOLC_NO_SUPPORT(log1p)
# undef CPPAD_BASE_ADOLC_NO_SUPPORT
}

sign
This required function is defined using the codassign function so that its adouble operation sequence does not depend on the value of x .
namespace CppAD {
    inline adouble sign(const adouble& x)
    {   adouble s_plus, s_minus, half(.5);
        // set s_plus to sign(x)/2,  except for case x == 0, s_plus = -.5
        condassign(s_plus,  +x, -half, +half);
        // set s_minus to -sign(x)/2, except for case x == 0, s_minus = -.5
        condassign(s_minus, -x, -half, +half);
        // set s to sign(x)
        return s_plus - s_minus;
    }
}

abs
This required function uses the adolc fabs function:
namespace CppAD {
    inline adouble abs(const adouble& x)
    {   return fabs(x); }
}

pow
This required function is defined by the Adolc package for the adouble base case.

numeric_limits
The following defines the CppAD numeric_limits for the type adouble:

namespace CppAD {
    CPPAD_NUMERIC_LIMITS(double, adouble)
}

to_string
The following defines the CppAD to_string function for the type adouble:
namespace CppAD {
    template <> struct to_string_struct<adouble>
    {   std::string operator()(const adouble& x)
        {   std::stringstream os;
            int n_digits = 1 + std::numeric_limits<double>::digits10;
            os << std::setprecision(n_digits);
            os << x.value();
            return os.str();
        }
    };
}

hash_code
It appears that an adouble object can have fields that are not initialized. This results in a valgrind error when these fields are used by the default hashing function. For this reason, the adouble class overrides the default definition.
namespace CppAD {
    inline unsigned short hash_code(const adouble& x)
    {   unsigned short code = 0;
        double value = x.value();
        if( value == 0.0 )
            return code;
        double log_x = std::log( fabs( value ) );
        // assume log( std::numeric_limits<double>::max() ) is near 700
        code = static_cast<unsigned short>(
            (CPPAD_HASH_TABLE_SIZE / 700 + 1) * log_x
        );
        code = code % CPPAD_HASH_TABLE_SIZE;
        return code;
    }
}
Note that after the hash codes match, the Identical function will be used to make sure two values are the same and one can replace the other. A more sophisticated implementation of the Identical function would detect which adouble values depend on the adouble independent variables (and hence can change).
Input File: include/cppad/example/base_adolc.hpp