44 | 44 |
|
45 | 45 |
namespace {
|
46 | 46 |
class Fun {
|
|
47 |
private:
|
|
48 |
const bool use_x_;
|
|
49 |
CppAD::ADFun<double> ode_ind_;
|
|
50 |
CppAD::ADFun<double> ode_dep_;
|
47 | 51 |
public:
|
48 | 52 |
// constructor
|
49 | |
Fun(bool use_x_) : use_x(use_x_)
|
|
53 |
Fun(bool use_x) : use_x_(use_x)
|
50 | 54 |
{ }
|
51 | 55 |
|
52 | 56 |
// compute f(t, x) both for double and AD<double>
|
53 | 57 |
template <class Scalar>
|
54 | 58 |
void Ode(
|
55 | |
const Scalar &t,
|
|
59 |
const Scalar &t,
|
56 | 60 |
const CPPAD_TESTVECTOR(Scalar) &x,
|
57 | 61 |
CPPAD_TESTVECTOR(Scalar) &f)
|
58 | 62 |
{ size_t n = x.size();
|
59 | 63 |
Scalar ti(1);
|
60 | 64 |
f[0] = Scalar(1);
|
61 | |
size_t i;
|
62 | |
for(i = 1; i < n; i++)
|
|
65 |
for(size_t i = 1; i < n; i++)
|
63 | 66 |
{ ti *= t;
|
64 | |
// convert int(size_t) to avoid warning
|
65 | |
// on _MSC_VER systems
|
66 | |
if( use_x )
|
67 | |
f[i] = int(i+1) * x[i-1];
|
|
67 |
if( use_x_ )
|
|
68 |
f[i] = Scalar(i+1) * x[i-1];
|
68 | 69 |
else
|
69 | |
f[i] = int(i+1) * ti;
|
|
70 |
f[i] = Scalar(i+1) * ti;
|
70 | 71 |
}
|
71 | 72 |
}
|
72 | 73 |
|
73 | 74 |
// compute partial of f(t, x) w.r.t. t using AD
|
74 | 75 |
void Ode_ind(
|
75 | |
const double &t,
|
|
76 |
const double &t,
|
76 | 77 |
const CPPAD_TESTVECTOR(double) &x,
|
77 | 78 |
CPPAD_TESTVECTOR(double) &f_t)
|
78 | 79 |
{ using namespace CppAD;
|
79 | 80 |
|
80 | 81 |
size_t n = x.size();
|
81 | |
CPPAD_TESTVECTOR(AD<double>) T(1);
|
82 | |
CPPAD_TESTVECTOR(AD<double>) X(n);
|
83 | |
CPPAD_TESTVECTOR(AD<double>) F(n);
|
84 | |
|
85 | |
// set argument values
|
86 | |
T[0] = t;
|
87 | |
size_t i;
|
88 | |
for(i = 0; i < n; i++)
|
89 | |
X[i] = x[i];
|
90 | |
|
91 | |
// declare independent variables
|
92 | |
Independent(T);
|
93 | |
|
94 | |
// compute f(t, x)
|
95 | |
this->Ode(T[0], X, F);
|
96 | |
|
97 | |
// define AD function object
|
98 | |
ADFun<double> fun(T, F);
|
99 | |
|
|
82 |
if( ode_ind_.size_var() == 0 )
|
|
83 |
{ // record function that evaluates f(t, x)
|
|
84 |
// with t as independent variable and x as dynamcic parameter
|
|
85 |
CPPAD_TESTVECTOR(AD<double>) at(1);
|
|
86 |
CPPAD_TESTVECTOR(AD<double>) ax(n);
|
|
87 |
CPPAD_TESTVECTOR(AD<double>) af(n);
|
|
88 |
|
|
89 |
// set argument values
|
|
90 |
at[0] = t;
|
|
91 |
size_t i;
|
|
92 |
for(i = 0; i < n; i++)
|
|
93 |
ax[i] = x[i];
|
|
94 |
|
|
95 |
// declare independent variables and dynamic parameters
|
|
96 |
size_t abort_op_index = 0;
|
|
97 |
bool record_compare = false;
|
|
98 |
Independent(at, abort_op_index, record_compare, ax);
|
|
99 |
|
|
100 |
// compute f(t, x)
|
|
101 |
this->Ode(at[0], ax, af);
|
|
102 |
|
|
103 |
// define AD function object
|
|
104 |
ADFun<double> fun(at, af);
|
|
105 |
|
|
106 |
// store result in ode_ind_ so can be re-used
|
|
107 |
ode_ind_.swap(fun);
|
|
108 |
assert( ode_ind_.size_var() != 0 );
|
|
109 |
assert( fun.size_var() == 0 );
|
|
110 |
}
|
100 | 111 |
// compute partial of f w.r.t t
|
101 | |
CPPAD_TESTVECTOR(double) dt(1);
|
102 | |
dt[0] = 1.;
|
103 | |
f_t = fun.Forward(1, dt);
|
|
112 |
CPPAD_TESTVECTOR(double) t_vec(1);
|
|
113 |
t_vec[0] = t;
|
|
114 |
ode_ind_.new_dynamic(x);
|
|
115 |
f_t = ode_ind_.Jacobian(t_vec); // partial f(t, x) w.r.t. t
|
104 | 116 |
}
|
105 | 117 |
|
106 | 118 |
// compute partial of f(t, x) w.r.t. x using AD
|
107 | 119 |
void Ode_dep(
|
108 | |
const double &t,
|
|
120 |
const double &t,
|
109 | 121 |
const CPPAD_TESTVECTOR(double) &x,
|
110 | 122 |
CPPAD_TESTVECTOR(double) &f_x)
|
111 | 123 |
{ using namespace CppAD;
|
112 | 124 |
|
113 | 125 |
size_t n = x.size();
|
114 | |
CPPAD_TESTVECTOR(AD<double>) T(1);
|
115 | |
CPPAD_TESTVECTOR(AD<double>) X(n);
|
116 | |
CPPAD_TESTVECTOR(AD<double>) F(n);
|
117 | |
|
118 | |
// set argument values
|
119 | |
T[0] = t;
|
120 | |
size_t i, j;
|
121 | |
for(i = 0; i < n; i++)
|
122 | |
X[i] = x[i];
|
123 | |
|
124 | |
// declare independent variables
|
125 | |
Independent(X);
|
126 | |
|
127 | |
// compute f(t, x)
|
128 | |
this->Ode(T[0], X, F);
|
129 | |
|
130 | |
// define AD function object
|
131 | |
ADFun<double> fun(X, F);
|
132 | |
|
|
126 |
if( ode_dep_.size_var() == 0 )
|
|
127 |
{ // record function that evaluates f(t, x)
|
|
128 |
// with x as independent variable and t as dynamcic parameter
|
|
129 |
CPPAD_TESTVECTOR(AD<double>) at(1);
|
|
130 |
CPPAD_TESTVECTOR(AD<double>) ax(n);
|
|
131 |
CPPAD_TESTVECTOR(AD<double>) af(n);
|
|
132 |
|
|
133 |
// set argument values
|
|
134 |
at[0] = t;
|
|
135 |
for(size_t i = 0; i < n; i++)
|
|
136 |
ax[i] = x[i];
|
|
137 |
|
|
138 |
// declare independent variables
|
|
139 |
size_t abort_op_index = 0;
|
|
140 |
bool record_compare = false;
|
|
141 |
Independent(ax, abort_op_index, record_compare, at);
|
|
142 |
|
|
143 |
// compute f(t, x)
|
|
144 |
this->Ode(at[0], ax, af);
|
|
145 |
|
|
146 |
// define AD function object
|
|
147 |
ADFun<double> fun(ax, af);
|
|
148 |
|
|
149 |
// store result in ode_dep_ so can be re-used
|
|
150 |
ode_dep_.swap(fun);
|
|
151 |
assert( ode_ind_.size_var() != 0 );
|
|
152 |
assert( fun.size_var() == 0 );
|
|
153 |
}
|
133 | 154 |
// compute partial of f w.r.t x
|
134 | |
CPPAD_TESTVECTOR(double) dx(n);
|
135 | |
CPPAD_TESTVECTOR(double) df(n);
|
136 | |
for(j = 0; j < n; j++)
|
137 | |
dx[j] = 0.;
|
138 | |
for(j = 0; j < n; j++)
|
139 | |
{ dx[j] = 1.;
|
140 | |
df = fun.Forward(1, dx);
|
141 | |
for(i = 0; i < n; i++)
|
142 | |
f_x [i * n + j] = df[i];
|
143 | |
dx[j] = 0.;
|
144 | |
}
|
145 | |
}
|
146 | |
|
147 | |
private:
|
148 | |
const bool use_x;
|
|
155 |
CPPAD_TESTVECTOR(double) t_vec(1), dx(n), df(n);
|
|
156 |
t_vec[0] = t;
|
|
157 |
ode_dep_.new_dynamic(t_vec);
|
|
158 |
f_x = ode_dep_.Jacobian(x); // partial f(t, x) w.r.t. x
|
|
159 |
}
|
|
160 |
|
149 | 161 |
|
150 | 162 |
};
|
151 | 163 |
}
|
152 | 164 |
|
153 | 165 |
bool rosen_34(void)
|
154 | 166 |
{ bool ok = true; // initial return value
|
155 | |
size_t i; // temporary indices
|
156 | 167 |
|
157 | 168 |
using CppAD::NearEqual;
|
158 | 169 |
double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
|
|
164 | 175 |
|
165 | 176 |
// xi = X(0)
|
166 | 177 |
CPPAD_TESTVECTOR(double) xi(n);
|
167 | |
for(i = 0; i <n; i++)
|
|
178 |
for(size_t i = 0; i <n; i++)
|
168 | 179 |
xi[i] = 0.;
|
169 | 180 |
|
170 | |
size_t use_x;
|
171 | |
for( use_x = 0; use_x < 2; use_x++)
|
|
181 |
for(size_t use_x = 0; use_x < 2; use_x++)
|
172 | 182 |
{ // function object depends on value of use_x
|
173 | 183 |
Fun F(use_x > 0);
|
174 | 184 |
|
|
177 | 187 |
xf = CppAD::Rosen34(F, M, ti, tf, xi, e);
|
178 | 188 |
|
179 | 189 |
double check = tf;
|
180 | |
for(i = 0; i < n; i++)
|
|
190 |
for(size_t i = 0; i < n; i++)
|
181 | 191 |
{ // check that error is always positive
|
182 | 192 |
ok &= (e[i] >= 0.);
|
183 | 193 |
// 4th order method is exact for i < 4
|