File: reverse_three.cpp

package info (click to toggle)
cppad 2025.00.00.2-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 11,552 kB
  • sloc: cpp: 112,594; sh: 5,972; ansic: 179; python: 71; sed: 12; makefile: 10
file content (142 lines) | stat: -rw-r--r-- 3,721 bytes parent folder | download | duplicates (2)
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
132
133
134
135
136
137
138
139
140
141
142
// 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
// ----------------------------------------------------------------------------

/*
{xrst_begin reverse_three.cpp}

Third Order Reverse Mode: Example and Test
##########################################

Taylor Coefficients
*******************

.. math::
   :nowrap:

   \begin{eqnarray}
      X(t) & = & x^{(0)} + x^{(1)} t + x^{(2)} t^2
      \\
      X^{(1)} (t) & = &  x^{(1)} + 2 x^{(2)} t
      \\
      X^{(2)} (t) & = &   2 x^{(2)}
   \end{eqnarray}

Thus, we need to be careful to properly account for the fact that
:math:`X^{(2)} (0) = 2 x^{(2)}`
(and similarly :math:`Y^{(2)} (0) = 2 y^{(2)}`).

{xrst_literal
   // BEGIN C++
   // END C++
}

{xrst_end reverse_three.cpp}
*/
// BEGIN C++
# include <cppad/cppad.hpp>
namespace { // ----------------------------------------------------------
// define the template function cases<Vector> in empty namespace
template <class Vector>
bool cases(void)
{  bool ok    = true;
   double eps = 10. * CppAD::numeric_limits<double>::epsilon();
   using CppAD::AD;
   using CppAD::NearEqual;

   // domain space vector
   size_t n = 2;
   CPPAD_TESTVECTOR(AD<double>) X(n);
   X[0] = 0.;
   X[1] = 1.;

   // declare independent variables and start recording
   CppAD::Independent(X);

   // range space vector
   size_t m = 1;
   CPPAD_TESTVECTOR(AD<double>) Y(m);
   Y[0] = X[0] * X[1];

   // create f : X -> Y and stop recording
   CppAD::ADFun<double> f(X, Y);

   // define x^0 and compute y^0 using user zero order forward
   Vector x0(n), y0(m);
   x0[0]    = 2.;
   x0[1]    = 3.;
   y0       = f.Forward(0, x0);

   // y^0 = F(x^0)
   double check;
   check    =  x0[0] * x0[1];
   ok      &= NearEqual(y0[0] , check, eps, eps);

   // define x^1 and compute y^1 using first order forward mode
   Vector x1(n), y1(m);
   x1[0] = 4.;
   x1[1] = 5.;
   y1    = f.Forward(1, x1);

   // Y^1 (x) = partial_t F( x^0 + x^1 * t )
   // y^1     = Y^1 (0)
   check = x1[0] * x0[1] + x0[0] * x1[1];
   ok   &= NearEqual(y1[0], check, eps, eps);

   // define x^2 and compute y^2 using second order forward mode
   Vector x2(n), y2(m);
   x2[0] = 6.;
   x2[1] = 7.;
   y2    = f.Forward(2, x2);

   // Y^2 (x) = partial_tt F( x^0 + x^1 * t + x^2 * t^2 )
   // y^2     = (1/2) *  Y^2 (0)
   check  = x2[0] * x0[1] + x1[0] * x1[1] + x0[0] * x2[1];
   ok    &= NearEqual(y2[0], check, eps, eps);

   // W(x)  = Y^0 (x) + 2 * Y^1 (x) + 3 * (1/2) * Y^2 (x)
   size_t p = 3;
   Vector dw(n*p), w(m*p);
   w[0] = 1.;
   w[1] = 2.;
   w[2] = 3.;
   dw   = f.Reverse(p, w);

   // check partial w.r.t x^0_0 of W(x)
   check = x0[1] + 2. * x1[1] + 3. * x2[1];
   ok   &= NearEqual(dw[0*p+0], check, eps, eps);

   // check partial w.r.t x^0_1 of W(x)
   check = x0[0] + 2. * x1[0] + 3. * x2[0];
   ok   &= NearEqual(dw[1*p+0], check, eps, eps);

   // check partial w.r.t x^1_0 of W(x)
   check = 2. * x0[1] + 3. * x1[1];
   ok   &= NearEqual(dw[0*p+1], check, eps, eps);

   // check partial w.r.t x^1_1 of W(x)
   check = 2. * x0[0] + 3. * x1[0];
   ok   &= NearEqual(dw[1*p+1], check, eps, eps);

   // check partial w.r.t x^2_0 of W(x)
   check = 3. * x0[1];
   ok   &= NearEqual(dw[0*p+2], check, eps, eps);

   // check partial w.r.t x^2_1 of W(x)
   check = 3. * x0[0];
   ok   &= NearEqual(dw[1*p+2], check, eps, eps);

   return ok;
}
} // End empty namespace
# include <vector>
# include <valarray>
bool reverse_three(void)
{  bool ok = true;
   ok &= cases< CppAD::vector  <double> >();
   ok &= cases< std::vector    <double> >();
   ok &= cases< std::valarray  <double> >();
   return ok;
}
// END C++