1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
// SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
// SPDX-FileContributor: 2003-22 Bradley M. Bell
// ----------------------------------------------------------------------------
/*
@begin zdouble.cpp@@
$spell
zdouble
$$
$section zdouble: Example and Test$$
$srcthisfile%0%// BEGIN C++%// END C++%1%$$
$end
*/
// BEGIN C++
# include <cppad/cppad.hpp>
namespace {
template <class Base> bool test_one(void)
{ bool ok = true;
Base eps99 = 99. * std::numeric_limits<double>::epsilon();
typedef CppAD::AD<Base> a1type;
typedef CppAD::AD<a1type> a2type;
// value during taping
size_t n = 2;
CPPAD_TESTVECTOR(Base) x(n);
x[0] = 0.0;
x[1] = 0.0;
// declare independent variable
CPPAD_TESTVECTOR(a2type) a2x(n);
for (size_t j = 0; j < n; j++)
a2x[j] = a2type( a1type(x[j]) );
Independent(a2x);
// zero and one as a2type values
a2type a2zero = a2type(0.0);
a2type a2one = a2type(1.0);
// h(x) = x[0] / x[1] if x[1] > x[0] else 1.0
a2type h_x = CondExpGt(a2x[1], a2x[0], a2x[0] / a2x[1], a2one);
// f(x) = h(x) if x[0] > 0.0 else 0.0
// = x[0] / x[1] if x[1] > x[0] and x[0] > 0.0
// = 1.0 if x[0] >= x[1] and x[0] > 0.0
// = 0.0 if x[0] <= 0.0
a2type f_x = CondExpGt(a2x[0], a2zero, h_x, a2one);
// define the function f(x)
size_t m = 1;
CPPAD_TESTVECTOR(a2type) a2y(m);
a2y[0] = f_x;
CppAD::ADFun<a1type> af1;
af1.Dependent(a2x, a2y);
// Define function g(x) = gradient of f(x)
CPPAD_TESTVECTOR(a1type) a1x(n), a1z(n), a1w(m);
for (size_t j = 0; j < n; j++)
a1x[j] = a1type(x[j]);
a1w[0] = a1type(1.0);
Independent(a1x);
af1.Forward(0, a1x);
a1z = af1.Reverse(1, a1w);
CppAD::ADFun<Base> g;
g.Dependent(a1x, a1z);
// check result for a case where f(x) = 0.0;
CPPAD_TESTVECTOR(Base) z(2);
x[0] = 0.0;
x[1] = 0.0;
z = g.Forward(0, x);
ok &= z[0] == 0.0;
ok &= z[1] == 0.0;
// check result for a case where f(x) = 1.0;
x[0] = 1.0;
x[1] = 0.5;
z = g.Forward(0, x);
ok &= z[0] == 0.0;
ok &= z[1] == 0.0;
// check result for a case where f(x) = x[0] / x[1];
x[0] = 1.0;
x[1] = 2.0;
z = g.Forward(0, x);
ok &= CppAD::NearEqual(z[0], 1.0/x[1], eps99, eps99);
ok &= CppAD::NearEqual(z[1], - x[0]/(x[1]*x[1]), eps99, eps99);
return ok;
}
bool test_two(void)
{ bool ok = true;
using CppAD::zdouble;
//
zdouble eps = CppAD::numeric_limits<zdouble>::epsilon();
ok &= eps == std::numeric_limits<double>::epsilon();
//
zdouble min = CppAD::numeric_limits<zdouble>::min();
ok &= min == std::numeric_limits<double>::min();
//
zdouble max = CppAD::numeric_limits<zdouble>::max();
ok &= max == std::numeric_limits<double>::max();
//
zdouble nan = CppAD::numeric_limits<zdouble>::quiet_NaN();
ok &= nan != nan;
//
int digits10 = CppAD::numeric_limits<zdouble>::digits10;
ok &= digits10 == std::numeric_limits<double>::digits10;
//
return ok;
}
}
bool zdouble(void)
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
using CppAD::zdouble;
//
ok &= test_one<zdouble>();
ok &= test_one<double>();
//
ok &= test_two();
//
return ok;
}
// END C++
|