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
// ----------------------------------------------------------------------------
/*
Old OdeRunge example now used just for valiadation testing of Runge45
*/
# include <cppad/cppad.hpp>
# include <iostream>
# include <cassert>
namespace { // BEGIN Empty namespace
class TestFun {
public:
TestFun(const CPPAD_TESTVECTOR(CppAD::AD<double>) &w_)
{ w.resize( w_.size() );
w = w_;
}
void Ode(
const CppAD::AD<double> &t,
const CPPAD_TESTVECTOR(CppAD::AD<double>) &x,
CPPAD_TESTVECTOR(CppAD::AD<double>) &f)
{
using CppAD::exp;
size_t n = x.size();
size_t i;
f[0] = 0.;
for(i = 1; i < n-1; i++)
f[i] = w[i] * x[i-1];
f[n-1] = x[0] * x[1];
}
private:
CPPAD_TESTVECTOR(CppAD::AD<double>) w;
};
} // END Empty namespace
bool Runge45(void)
{ bool ok = true;
using namespace CppAD;
using CppAD::NearEqual;
double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
size_t i;
size_t j;
size_t k;
size_t n = 6;
size_t m = n - 1;
CPPAD_TESTVECTOR(AD<double>) x(n);
AD<double> t0 = 0.;
AD<double> t1 = 2.;
size_t nstep = 2;
// vector of independent variables
CPPAD_TESTVECTOR(AD<double>) w(m);
for(i = 0; i < m; i++)
w[i] = double(i);
Independent(w);
// construct function object using independent variables
TestFun fun(w);
// initial value of x
CPPAD_TESTVECTOR(AD<double>) x0(n);
for(i = 0; i < n; i++)
x0[i] = 0.;
x0[0] = exp( w[0] );
// solve the differential equation
x = Runge45(fun, nstep, t0, t1, x0);
// create f : w -> x and vectors for evaluating derivatives
ADFun<double> f(w, x);
CPPAD_TESTVECTOR(double) q( f.Domain() );
CPPAD_TESTVECTOR(double) r( f.Range() );
// for i < n-1,
// x[i](2) = exp( w[0] ) * (w[1] / 1) * ... * (w[i] / i) * 2^i
AD<double> xi2 = exp(w[0]);
for(i = 0; i < n-1; i++)
{ ok &= NearEqual(x[i], xi2, eps99, eps99);
if( i < n-2 )
xi2 *= w[i+1] * 2. / double(i+1);
}
// x[n-1](2) = exp(2 * w[0]) * w[1] * 2^2 / 2
xi2 = exp(2. * w[0]) * w[1] * 2.;
ok &= NearEqual(x[n-1], xi2, eps99, eps99);
// the partial of x[i](2) with respect to w[j] is
// x[i](2) / w[j] if 0 < j <= i < n-1
// x[i](2) if j == 0 and i < n-1
// 2*x[i](2) if j == 0 and i = n-1
// x[i](2) / w[j] if j == 1 and i = n-1
// zero otherwise
for(i = 0; i < n-1; i++)
{ // compute partials of x[i]
for(k = 0; k < n; k++)
r[k] = 0.;
r[i] = 1.;
q = f.Reverse(1,r);
for(j = 0; j < m; j++)
{ // check partial of x[i] w.r.t w[j]
if (j == 0 )
ok &= NearEqual(q[j], x[i], eps99, eps99);
else if( j <= i )
ok &= NearEqual(
q[j], x[i]/w[j], 1e-14, 1e-14);
else
ok &= NearEqual(q[j], 0., eps99, eps99);
}
}
// compute partials of x[n-1]
i = n-1;
for(k = 0; k < n; k++)
r[k] = 0.;
r[i] = 1.;
q = f.Reverse(1,r);
for(j = 0; j < m; j++)
{ // check partial of x[n-1] w.r.t w[j]
if (j == 0 )
ok &= NearEqual(q[j], 2.*x[i], eps99, eps99);
else if( j == 1 )
ok &= NearEqual(
q[j], x[i]/w[1], 1e-14, 1e-14);
else
ok &= NearEqual(q[j], 0., eps99, eps99);
}
return ok;
}
|