1 /* --------------------------------------------------------------------------
2 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
3 
4 CppAD is distributed under the terms of the
5              Eclipse Public License Version 2.0.
6 
7 This Source Code may also be made available under the following
8 Secondary License when the conditions for such availability set forth
9 in the Eclipse Public License, Version 2.0 are satisfied:
10       GNU General Public License, Version 2.0 or later.
11 ---------------------------------------------------------------------------- */
12 
13 /*
14 $begin base2ad.cpp$$
15 $spell
16     Taylor
17     Cpp
18     const
19     std
20     Adolc
21     adouble
22 $$
23 
24 $section Taylor's Ode Solver: base2ad Example and Test$$
25 
26 $head See Also$$
27 $cref taylor_ode.cpp$$, $cref mul_level_ode.cpp$$
28 
29 $head Purpose$$
30 This is a realistic example using $cref base2ad$$ to create
31 an $codei%AD<%Base%>%$$ function from an $icode Base$$ function.
32 The function represents an ordinary differential equation.
33 It is differentiated with respect to
34 its $cref/variables/glossary/Variable/$$.
35 These derivatives are used by the $cref taylor_ode$$ method.
36 This solution is then differentiated with respect to
37 the functions $cref/dynamic parameters/glossary/Parameter/Dynamic/$$.
38 
39 $head ODE$$
40 For this example the function
41 $latex y : \B{R} \times \B{R}^n \rightarrow \B{R}^n$$ is defined by
42 $latex y(0, x) = 0$$ and
43 $latex \partial_t y(t, x) = g(y, x)$$ where
44 $latex g : \B{R}^n \times \B{R}^n \rightarrow \B{R}^n$$ is defined by
45 $latex \[
46     g(y, x) =
47     \left( \begin{array}{c}
48             x_0     \\
49             x_1 y_0 \\
50             \vdots  \\
51             x_{n-1} y_{n-2}
52     \end{array} \right)
53 \] $$
54 
55 $head ODE Solution$$
56 The solution for this example can be calculated by
57 starting with the first row and then using the solution
58 for the first row to solve the second and so on.
59 Doing this we obtain
60 $latex \[
61     y(t, x ) =
62     \left( \begin{array}{c}
63         x_0 t                  \\
64         x_1 x_0 t^2 / 2        \\
65         \vdots                 \\
66         x_{n-1} x_{n-2} \ldots x_0 t^n / n !
67     \end{array} \right)
68 \] $$
69 
70 $head Derivative of ODE Solution$$
71 Differentiating the solution above,
72 with respect to the parameter vector $latex x$$,
73 we notice that
74 $latex \[
75 \partial_x y(t, x ) =
76 \left( \begin{array}{cccc}
77 y_0 (t,x) / x_0      & 0                   & \cdots & 0      \\
78 y_1 (t,x) / x_0      & y_1 (t,x) / x_1     & 0      & \vdots \\
79 \vdots               & \vdots              & \ddots & 0      \\
80 y_{n-1} (t,x) / x_0  & y_{n-1} (t,x) / x_1 & \cdots & y_{n-1} (t,x) / x_{n-1}
81 \end{array} \right)
82 \] $$
83 
84 $head Taylor's Method Using AD$$
85 We define the function $latex z(t, x)$$ by the equation
86 $latex \[
87     z ( t , x ) = g[ y ( t , x ), x ]
88 \] $$
89 see $cref taylor_ode$$ for the method used to compute the
90 Taylor coefficients w.r.t $latex t$$ of $latex y(t, x)$$.
91 
92 $head Source$$
93 $srcthisfile%0%// BEGIN C++%// END C++%1%$$
94 
95 $end
96 --------------------------------------------------------------------------
97 */
98 // BEGIN C++
99 
100 # include <cppad/cppad.hpp>
101 
102 // =========================================================================
103 namespace { // BEGIN empty namespace
104 
105 typedef CppAD::AD<double>                  a_double;
106 
107 typedef CPPAD_TESTVECTOR(double)           d_vector;
108 typedef CPPAD_TESTVECTOR(a_double)         a_vector;
109 
110 typedef CppAD::ADFun<double>               fun_double;
111 typedef CppAD::ADFun<a_double, double>     afun_double;
112 
113 // -------------------------------------------------------------------------
114 // class definition for C++ function object that defines ODE
115 class Ode {
116 private:
117     // copy of x that is set by constructor and used by g(y)
118     a_vector x_;
119 public:
120     // constructor
Ode(const a_vector & x)121     Ode(const a_vector& x) : x_(x)
122     { }
123     // the function g(y) given the parameter vector x
operator ()(const a_vector & y) const124     a_vector operator() (const a_vector& y) const
125     {   size_t n = y.size();
126         a_vector g(n);
127         g[0] = x_[0];
128         for(size_t i = 1; i < n; i++)
129             g[i] = x_[i] * y[i-1];
130         //
131         return g;
132     }
133 };
134 
135 // -------------------------------------------------------------------------
136 // Routine that uses Taylor's method to solve ordinary differential equaitons
taylor_ode(afun_double & fun_g,size_t order,size_t nstep,const a_double & dt,const a_vector & y_ini)137 a_vector taylor_ode(
138     afun_double&     fun_g   ,  // function that defines the ODE
139     size_t           order   ,  // order of Taylor's method used
140     size_t           nstep   ,  // number of steps to take
141     const a_double&  dt      ,  // Delta t for each step
142     const a_vector&  y_ini)     // y(t) at the initial time
143 {
144     // number of variables in the ODE
145     size_t n = y_ini.size();
146 
147     // initialize y
148     a_vector y = y_ini;
149 
150     // loop with respect to each step of Taylors method
151     for(size_t s = 0; s < nstep; s++)
152     {
153         // initialize
154         a_vector y_k   = y;
155         a_double dt_k  = a_double(1.0);
156         a_vector next  = y;
157 
158         for(size_t k = 0; k < order; k++)
159         {
160             // evaluate k-th order Taylor coefficient z^{(k)} (t)
161             a_vector z_k = fun_g.Forward(k, y_k);
162 
163             // dt^{k+1}
164             dt_k *= dt;
165 
166             // y^{(k+1)}
167             for(size_t i = 0; i < n; i++)
168             {   // y^{(k+1)}
169                 y_k[i] = z_k[i] / a_double(k + 1);
170 
171                 // add term for k+1 Taylor coefficient
172                 // to solution for next y
173                 next[i] += y_k[i] * dt_k;
174             }
175         }
176 
177         // take step
178         y = next;
179     }
180     return y;
181 }
182 } // END empty namespace
183 
184 // ==========================================================================
185 // Routine that tests alogirhtmic differentiation of solutions computed
186 // by the routine taylor_ode.
base2ad(void)187 bool base2ad(void)
188 {   bool ok = true;
189     double eps = 100. * std::numeric_limits<double>::epsilon();
190 
191     // number of components in differential equation
192     size_t n = 4;
193 
194     // record function g(y, x)
195     // with y as the independent variables and x as dynamic parameters
196     a_vector  ay(n), ax(n);
197     for(size_t i = 0; i < n; i++)
198         ay[i] = ax[i] = double(i + 1);
199     CppAD::Independent(ay, ax);
200 
201     // fun_g
202     Ode G(ax);
203     a_vector ag = G(ay);
204     fun_double fun_g(ay, ag);
205 
206 
207     // afun_g
208     afun_double afun_g( fun_g.base2ad() ); // differential equation
209 
210     // other arguments to taylor_ode
211     size_t   order = n;       // order of Taylor's method used
212     size_t   nstep = 2;       // number of steps to take
213     a_double adt   = 1.;      // Delta t for each step
214     a_vector ay_ini(n);       // initial value of y
215     for(size_t i = 0; i < n; i++)
216         ay_ini[i] = 0.;
217 
218     // declare x as independent variables
219     CppAD::Independent(ax);
220 
221     // the independent variables if this function are
222     // the dynamic parameters in afun_g
223     afun_g.new_dynamic(ax);
224 
225     // integrate the differential equation
226     a_vector ay_final;
227     ay_final = taylor_ode(afun_g, order, nstep, adt, ay_ini);
228 
229     // define differentiable fucntion object f(x) = y_final(x)
230     // that computes its derivatives in double
231     CppAD::ADFun<double> fun_f(ax, ay_final);
232 
233     // double version of ax
234     d_vector x(n);
235     for(size_t i = 0; i < n; i++)
236         x[i] = Value( ax[i] );
237 
238     // check function values
239     double check = 1.;
240     double t     = double(nstep) * Value(adt);
241     for(size_t i = 0; i < n; i++)
242     {   check *= x[i] * t / double(i + 1);
243         ok &= CppAD::NearEqual(Value(ay_final[i]), check, eps, eps);
244     }
245 
246     // There appears to be a bug in g++ version 4.4.2 because it generates
247     // a warning for the equivalent form
248     // d_vector jac = fun_f.Jacobian(x);
249     d_vector jac ( fun_f.Jacobian(x) );
250 
251     // check Jacobian
252     for(size_t i = 0; i < n; i++)
253     {   for(size_t j = 0; j < n; j++)
254         {   double jac_ij = jac[i * n + j];
255             if( i < j )
256                 check = 0.;
257             else
258                 check = Value( ay_final[i] ) / x[j];
259             ok &= CppAD::NearEqual(jac_ij, check, eps, eps);
260         }
261     }
262     return ok;
263 }
264 
265 // END C++
266