File: mul_level.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 (144 lines) | stat: -rw-r--r-- 3,818 bytes parent folder | download
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
143
144
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
// SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
// SPDX-FileContributor: 2003-24 Bradley M. Bell
// ----------------------------------------------------------------------------

/*
{xrst_begin mul_level.cpp}
{xrst_spell
  adouble
  dx
}

Multiple Level of AD: Example and Test
######################################

See Also
********
:ref:`base2ad.cpp-name`

Purpose
*******
In this example, we use ``AD< AD<double> >`` (level two taping),
the compute values of the function :math:`f : \B{R}^n \rightarrow \B{R}` where

.. math::

   f(x) = \frac{1}{2} \left( x_0^2 + \cdots + x_{n-1}^2 \right)

We then use ``AD<double>`` (level one taping) to compute
the directional derivative

.. math::

   f^{(1)} (x) * v  = x_0 v_0 + \cdots + x_{n-1} v_{n-1}

where :math:`v \in \B{R}^n`.
We then use ``double`` (no taping) to compute

.. math::

   \frac{d}{dx} \left[ f^{(1)} (x) * v \right] = v

This is only meant as an example of multiple levels of taping.
The example :ref:`hes_times_dir.cpp-name` computes the same value more
efficiently by using the identity:

.. math::

   \frac{d}{dx} \left[ f^{(1)} (x) * v \right] = f^{(2)} (x) * v

The example :ref:`mul_level_adolc.cpp-name` computes the same values using
Adolc's type ``adouble`` and CppAD's type ``AD<adouble>`` .

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

{xrst_end mul_level.cpp}
*/
// BEGIN C++

# include <cppad/cppad.hpp>

namespace {
   // f(x) = |x|^2 / 2 = .5 * ( x[0]^2 + ... + x[n-1]^2 )
   template <class Type>
   Type f(const CPPAD_TESTVECTOR(Type)& x)
   {  Type sum;

      sum  = 0.;
      size_t i = size_t(x.size());
      for(i = 0; i < size_t(x.size()); i++)
         sum += x[i] * x[i];

      return .5 * sum;
   }
}

bool mul_level(void)
{  bool ok = true;                          // initialize test result

   typedef CppAD::AD<double>   a1type;    // for one level of taping
   typedef CppAD::AD<a1type>    a2type;    // for two levels of taping
   size_t n = 5;                           // dimension for example
   size_t j;                               // a temporary index variable

   // 10 times machine epsilon
   double eps = 10. * std::numeric_limits<double>::epsilon();

   CPPAD_TESTVECTOR(double) x(n);
   CPPAD_TESTVECTOR(a1type)  a1x(n), a1v(n), a1dy(1) ;
   CPPAD_TESTVECTOR(a2type)  a2x(n), a2y(1);

   // Values for the independent variables while taping the function f(x)
   for(j = 0; j < n; j++)
      a2x[j] = a1x[j] = x[j] = double(j);
   // Declare the independent variable for taping f(x)
   CppAD::Independent(a2x);

   // Use AD< AD<double> > to tape the evaluation of f(x)
   a2y[0] = f(a2x);

   // Declare a1f as the corresponding ADFun< AD<double> >
   // (make sure we do not run zero order forward during constructor)
   CppAD::ADFun<a1type> a1f;
   a1f.Dependent(a2x, a2y);

   // Values for the independent variables while taping f'(x) * v
   // Declare the independent variable for taping f'(x) * v
   // (Note we did not have to tape the creationg of a1f.)
   CppAD::Independent(a1x);

   // set the argument value x for computing f'(x) * v
   a1f.Forward(0, a1x);
   // compute f'(x) * v
   for(j = 0; j < n; j++)
      a1v[j] = double(n - j);
   a1dy = a1f.Forward(1, a1v);

   // declare g as ADFun<double> function corresponding to f'(x) * v
   CppAD::ADFun<double> g;
   g.Dependent(a1x, a1dy);

   // optimize out operations not necessary for function f'(x) * v
   g.optimize();

   // Evaluate f'(x) * v
   g.Forward(0, x);

   // compute the d/dx of f'(x) * v = f''(x) * v = v
   CPPAD_TESTVECTOR(double) w(1);
   CPPAD_TESTVECTOR(double) dw(n);
   w[0] = 1.;
   dw   = g.Reverse(1, w);

   for(j = 0; j < n; j++)
      ok &= CppAD::NearEqual(dw[j], a1v[j], eps, eps);

   return ok;
}
// END C++