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