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}} }@)@
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. It returns true if it succeeds and false otherwise. 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 IdenticalPar(const adouble &x)
     {     return false; }
     inline bool IdenticalZero(const adouble &x)
     {     return false; }
     inline bool IdenticalOne(const adouble &x)
     {     return false; }
     inline bool IdenticalEqualPar(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, asin, atan, cos, cosh, exp, fabs, log, sin, sinh, sqrt, tan.

erf, asinh, acosh, atanh, expm1, log1p
If the erf, asinh, acosh, atanh, expm1, log1p , functions are supported by the compiler, they must also be supported by a Base type; The adolc package does not support these functions so make their use 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;                                               \
    }
# if CPPAD_USE_CPLUSPLUS_2011
     CPPAD_BASE_ADOLC_NO_SUPPORT(erf)
     CPPAD_BASE_ADOLC_NO_SUPPORT(asinh)
     CPPAD_BASE_ADOLC_NO_SUPPORT(acosh)
     CPPAD_BASE_ADOLC_NO_SUPPORT(atanh)
     CPPAD_BASE_ADOLC_NO_SUPPORT(expm1)
     CPPAD_BASE_ADOLC_NO_SUPPORT(log1p)
# endif
# 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: cppad/example/base_adolc.hpp