--------------------------------------------------------- lines 8-353 of file: include/cppad/example/base_adolc.hpp --------------------------------------------------------- {xrst_begin base_adolc.hpp} {xrst_spell acosh adouble asinh atrig azmul codassign condassign erfc expm valgrind } Enable use of AD where Base is Adolc's adouble Type ######################################################### Syntax ****** | # ``include `` {xrst_toc_hidden example/general/mul_level_adolc.cpp } Example ******* The file :ref:`mul_level_adolc.cpp-name` contains an example use of Adolc's ``adouble`` type for a CppAD *Base* type. The file :ref:`mul_level_adolc_ode.cpp-name` 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 ```` , but it needs to include parts of CppAD that are used by this file. This is done with the following include commands: {xrst_spell_off} {xrst_code cpp} */ # include # include /* {xrst_code} {xrst_spell_on} CondExpOp ********* The type ``adouble`` supports a conditional assignment function with the syntax ``condassign`` ( *a* , *b* , *c* , *d* ) 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 :ref:`CondExp-name` function). {xrst_spell_off} {xrst_code cpp} */ 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; } } /* {xrst_code} {xrst_spell_on} CondExpRel ********** The :ref:`CPPAD_COND_EXP_REL` macro invocation {xrst_spell_off} {xrst_code cpp} */ namespace CppAD { CPPAD_COND_EXP_REL(adouble) } /* {xrst_code} {xrst_spell_on} 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: {xrst_spell_off} {xrst_code cpp} */ 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; } } /* {xrst_code} {xrst_spell_on} 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. {xrst_spell_off} {xrst_code cpp} */ 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; } } /* {xrst_code} {xrst_spell_on} Integer ******* {xrst_spell_off} {xrst_code cpp} */ inline int Integer(const adouble &x) { return static_cast( x.getValue() ); } /* {xrst_code} {xrst_spell_on} azmul ***** {xrst_spell_off} {xrst_code cpp} */ namespace CppAD { CPPAD_AZMUL( adouble ) } /* {xrst_code} {xrst_spell_on} Ordered ******* {xrst_spell_off} {xrst_code cpp} */ 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); } } /* {xrst_code} {xrst_spell_on} Unary Standard Math ******************* The following :ref:`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: {xrst_spell_off} {xrst_code cpp} */ 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 } /* {xrst_code} {xrst_spell_on} sign **** This :ref:`required` function is defined using the ``codassign`` function so that its ``adouble`` operation sequence does not depend on the value of *x* . {xrst_spell_off} {xrst_code cpp} */ 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; } } /* {xrst_code} {xrst_spell_on} abs *** This :ref:`required` function uses the adolc ``fabs`` function: {xrst_spell_off} {xrst_code cpp} */ namespace CppAD { inline adouble abs(const adouble& x) { return fabs(x); } } /* {xrst_code} {xrst_spell_on} pow *** This :ref:`required` function is defined by the Adolc package for the ``adouble`` base case. numeric_limits ************** The following defines the CppAD :ref:`numeric_limits-name` for the type ``adouble`` : {xrst_spell_off} {xrst_code cpp} */ namespace CppAD { CPPAD_NUMERIC_LIMITS(double, adouble) } /* {xrst_code} {xrst_spell_on} to_string ********* The following defines the CppAD :ref:`to_string-name` function for the type ``adouble`` : {xrst_spell_off} {xrst_code cpp} */ namespace CppAD { template <> struct to_string_struct { std::string operator()(const adouble& x) { std::stringstream os; int n_digits = 1 + std::numeric_limits::digits10; os << std::setprecision(n_digits); os << x.value(); return os.str(); } }; } /* {xrst_code} {xrst_spell_on} 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 :ref:`base_hash@Default` hashing function. For this reason, the ``adouble`` class overrides the default definition. {xrst_spell_off} {xrst_code cpp} */ 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::max() ) is near 700 code = static_cast( (CPPAD_HASH_TABLE_SIZE / 700 + 1) * log_x ); code = code % CPPAD_HASH_TABLE_SIZE; return code; } } /* {xrst_code} {xrst_spell_on} Note that after the hash codes match, the :ref:`base_adolc.hpp@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). {xrst_end base_adolc.hpp}