\(\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}} }\)
base_adolc.hpp¶
View page sourceEnable 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
( 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 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).