00001 #ifndef INDII_ML_SDE_STOCHASTICADAPTIVERUNGEKUTTA_HPP
00002 #define INDII_ML_SDE_STOCHASTICADAPTIVERUNGEKUTTA_HPP
00003
00004 #include "StochasticDifferentialModel.hpp"
00005 #include "StochasticNumericalSolver.hpp"
00006
00007 namespace indii {
00008 namespace ml {
00009 namespace sde {
00010
00011 template <class DT, class DDT>
00012 class StochasticAdaptiveRungeKuttaHelper;
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 template <class DT = indii::ml::aux::matrix,
00050 class DDT = indii::ml::aux::zero_matrix>
00051 class StochasticAdaptiveRungeKutta :
00052 public indii::ml::sde::StochasticNumericalSolver {
00053
00054 friend class indii::ml::sde::StochasticAdaptiveRungeKuttaHelper<DT,DDT>;
00055
00056 public:
00057
00058
00059
00060
00061
00062
00063
00064
00065 StochasticAdaptiveRungeKutta(StochasticDifferentialModel<DT,DDT>* model);
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 StochasticAdaptiveRungeKutta(StochasticDifferentialModel<DT,DDT>* model,
00076 const indii::ml::aux::vector& y0);
00077
00078
00079
00080
00081 virtual ~StochasticAdaptiveRungeKutta();
00082
00083 virtual double step(double upper);
00084
00085 virtual double stepBack(double lower);
00086
00087 virtual int calculateDerivativesForward(double t, const double y[],
00088 double dydt[]);
00089
00090 virtual int calculateDerivativesBackward(double t, const double y[],
00091 double dydt[]);
00092
00093 private:
00094
00095
00096
00097 StochasticDifferentialModel<DT,DDT>* model;
00098
00099
00100
00101
00102 indii::ml::aux::vector a;
00103
00104
00105
00106
00107 DT B;
00108
00109
00110
00111
00112 std::vector<DDT> dBdy;
00113
00114
00115
00116
00117 static const gsl_odeiv_step_type* gslStepType;
00118
00119 };
00120
00121
00122
00123
00124
00125
00126
00127
00128 template <class DT, class DDT>
00129 class StochasticAdaptiveRungeKuttaHelper {
00130 public:
00131 static int calculateDerivativesForward(double t, const double y[],
00132 double dydt[], StochasticAdaptiveRungeKutta<DT,DDT>* sde);
00133 };
00134
00135
00136
00137
00138
00139
00140 template <class DT>
00141 class StochasticAdaptiveRungeKuttaHelper<DT,indii::ml::aux::zero_matrix> {
00142 public:
00143 static int calculateDerivativesForward(double t, const double y[],
00144 double dydt[],
00145 StochasticAdaptiveRungeKutta<DT,indii::ml::aux::zero_matrix>* sde);
00146 };
00147
00148
00149
00150 }
00151 }
00152 }
00153
00154 #include "boost/numeric/ublas/operation.hpp"
00155 #include "boost/numeric/ublas/operation_sparse.hpp"
00156
00157 #include <assert.h>
00158
00159 #include <gsl/gsl_errno.h>
00160
00161 template <class DT, class DDT>
00162 const gsl_odeiv_step_type* indii::ml::sde::StochasticAdaptiveRungeKutta<DT,DDT>::gslStepType
00163 = gsl_odeiv_step_rkf45;
00164
00165 template <class DT, class DDT>
00166 indii::ml::sde::StochasticAdaptiveRungeKutta<DT,DDT>::StochasticAdaptiveRungeKutta(
00167 StochasticDifferentialModel<DT,DDT>* model) :
00168 StochasticNumericalSolver(model->getDimensions(),
00169 model->getNoiseDimensions()), model(model), a(model->getDimensions()),
00170 B(model->getDimensions(), model->getNoiseDimensions()) {
00171 unsigned int i;
00172 DDT dBdyi(model->getDimensions(), model->getNoiseDimensions());
00173
00174 a.clear();
00175 B.clear();
00176
00177 for (i = 0; i < model->getDimensions(); i++) {
00178 dBdy.push_back(dBdyi);
00179 }
00180
00181 setStepType(gslStepType);
00182 }
00183
00184 template <class DT, class DDT>
00185 indii::ml::sde::StochasticAdaptiveRungeKutta<DT,DDT>::StochasticAdaptiveRungeKutta(
00186 StochasticDifferentialModel<DT,DDT>* model,
00187 const indii::ml::aux::vector& y0) : StochasticNumericalSolver(y0,
00188 model->getNoiseDimensions()), model(model), a(model->getDimensions()),
00189 B(model->getDimensions(), model->getNoiseDimensions()) {
00190
00191 assert (y0.size() == model->getDimensions());
00192
00193 unsigned int i;
00194 DDT dBdyi(model->getDimensions(), model->getNoiseDimensions());
00195
00196 a.clear();
00197 B.clear();
00198
00199 for (i = 0; i < model->getDimensions(); i++) {
00200 dBdy.push_back(dBdyi);
00201 }
00202
00203 setStepType(gslStepType);
00204 }
00205
00206 template <class DT, class DDT>
00207 indii::ml::sde::StochasticAdaptiveRungeKutta<DT,DDT>::~StochasticAdaptiveRungeKutta() {
00208
00209 }
00210
00211 template <class DT, class DDT>
00212 double indii::ml::sde::StochasticAdaptiveRungeKutta<DT,DDT>::step(
00213 double upper) {
00214
00215
00216
00217
00218
00219
00220 assert (upper > t);
00221
00222 double ts, ts_new;
00223 double h, h_new;
00224 bool stepDecreased;
00225 int err;
00226 unsigned int i;
00227
00228
00229 if (maxStepSize > 0.0 && stepSize > maxStepSize) {
00230 stepSize = maxStepSize;
00231 }
00232 ts = t + stepSize;
00233 if (ts > upper) {
00234 ts = upper;
00235 }
00236
00237
00238 memcpy(gslEvolve->y0, y, gslEvolve->dimension*sizeof(double));
00239
00240
00241 if (gslStep->type->can_use_dydt_in) {
00242 err = GSL_ODEIV_FN_EVAL(&gslForwardSystem, t, y, gslEvolve->dydt_in);
00243 assert (err == GSL_SUCCESS);
00244 }
00245
00246 do {
00247 sampleNoise(&ts);
00248 h = ts - t;
00249
00250
00251 if (gslStep->type->can_use_dydt_in) {
00252 err = gsl_odeiv_step_apply(gslStep, t, h, y, gslEvolve->yerr,
00253 gslEvolve->dydt_in, gslEvolve->dydt_out, &gslForwardSystem);
00254 } else {
00255 err = gsl_odeiv_step_apply(gslStep, t, h, y, gslEvolve->yerr,
00256 NULL, gslEvolve->dydt_out, &gslForwardSystem);
00257 }
00258 assert (err == GSL_SUCCESS);
00259
00260 gslEvolve->last_step = h;
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 err = gslControl->type->hadjust(gslControl->state, gslStep->dimension,
00283 gslStep->type->order(gslStep->state) / 2, y, gslEvolve->yerr,
00284 gslEvolve->dydt_out, &h);
00285
00286 stepDecreased = false;
00287 if (err == GSL_ODEIV_HADJ_DEC) {
00288
00289 ts_new = t + h;
00290 if (ts_new > t && ts_new < ts) {
00291 h_new = ts_new - t;
00292 if (h_new > 0.0 && h_new < gslEvolve->last_step) {
00293
00294 ts = ts_new;
00295 memcpy(y, gslEvolve->y0, gslEvolve->dimension*sizeof(double));
00296 stepDecreased = true;
00297 } else {
00298
00299 h = gslEvolve->last_step;
00300 }
00301 } else {
00302
00303 h = gslEvolve->last_step;
00304 }
00305 }
00306 } while (stepDecreased);
00307
00308
00309 stepSize = h;
00310
00311
00312 t = ts;
00313
00314
00315 tf.pop();
00316 dWf.pop();
00317
00318
00319 assert (tf.empty() || t < tf.top());
00320 assert (t <= upper);
00321
00322 return t;
00323 }
00324
00325 template <class DT, class DDT>
00326 inline double indii::ml::sde::StochasticAdaptiveRungeKutta<DT,DDT>::stepBack(
00327 double lower) {
00328 double t = NumericalSolver::stepBack(lower);
00329
00330 return t;
00331 }
00332
00333 template <class DT, class DDT>
00334 inline int indii::ml::sde::StochasticAdaptiveRungeKutta<DT,DDT>::calculateDerivativesForward(
00335 double ts, const double y[], double dydt[]) {
00336 return StochasticAdaptiveRungeKuttaHelper<DT,DDT>::calculateDerivativesForward(
00337 ts, y, dydt, this);
00338 }
00339
00340 template <class DT, class DDT>
00341 inline int indii::ml::sde::StochasticAdaptiveRungeKutta<DT,DDT>::calculateDerivativesBackward(
00342 double t, const double y[], double dydt[]) {
00343
00344
00345 int result = calculateDerivativesForward(2.0 * base - t, y, dydt);
00346
00347 if (result == GSL_SUCCESS) {
00348
00349 size_t i;
00350 for (i = 0; i < dimensions; i++) {
00351 dydt[i] *= -1.0;
00352 }
00353 }
00354
00355 return result;
00356 }
00357
00358 template <class DT>
00359 inline int
00360 indii::ml::sde::StochasticAdaptiveRungeKuttaHelper<DT,indii::ml::aux::zero_matrix>::calculateDerivativesForward(
00361 double ts, const double y[], double dydt[],
00362 StochasticAdaptiveRungeKutta<DT,indii::ml::aux::zero_matrix>* sde) {
00363 namespace aux = indii::ml::aux;
00364 namespace ublas = boost::numeric::ublas;
00365
00366 StochasticDifferentialModel<DT,aux::zero_matrix>& model = *sde->model;
00367 aux::vector& a = sde->a;
00368 DT& B = sde->B;
00369
00370 unsigned int i;
00371 const unsigned int N = model.getDimensions();
00372 const unsigned int W = model.getNoiseDimensions();
00373 const double t = sde->getTime();
00374 double delta;
00375 if (sde->tf.empty()) {
00376 delta = 0.0;
00377 } else {
00378 delta = sde->tf.top() - t;
00379 }
00380
00381 aux::vector x(N);
00382 aux::arrayToVector(y, x);
00383
00384 model.calculateDrift(ts, x, a);
00385 assert (a.size() == N);
00386
00387 if (delta > 0.0) {
00388 model.calculateDiffusion(ts, x, B);
00389 assert (B.size1() == N && B.size2() == W);
00390 ublas::axpy_prod(B, sde->dWf.top() / delta, a, false);
00391 }
00392 aux::vectorToArray(a, dydt);
00393
00394 return GSL_SUCCESS;
00395 }
00396
00397 template <class DT, class DDT>
00398 inline int
00399 indii::ml::sde::StochasticAdaptiveRungeKuttaHelper<DT,DDT>::calculateDerivativesForward(
00400 double ts, const double y[], double dydt[],
00401 StochasticAdaptiveRungeKutta<DT,DDT>* sde) {
00402 namespace aux = indii::ml::aux;
00403 namespace ublas = boost::numeric::ublas;
00404
00405 StochasticDifferentialModel<DT,DDT>& model = *sde->model;
00406 aux::vector& a = sde->a;
00407 DT& B = sde->B;
00408 std::vector<DDT>& dBdy = sde->dBdy;
00409
00410 unsigned int i;
00411 const unsigned int N = model.getDimensions();
00412 const unsigned int W = model.getNoiseDimensions();
00413 const double t = sde->getTime();
00414 double delta;
00415 if (sde->tf.empty()) {
00416 delta = 0.0;
00417 } else {
00418 delta = sde->tf.top() - t;
00419 }
00420
00421 aux::vector x(N);
00422 aux::arrayToVector(y, x);
00423
00424 model.calculateDrift(ts, x, a);
00425 assert (a.size() == N);
00426
00427 if (delta > 0.0) {
00428 model.calculateDiffusion(ts, x, B);
00429 assert (B.size1() == N && B.size2() == W);
00430
00431 model.calculateDiffusionDerivatives(ts, x, dBdy);
00432 assert (dBdy.size() == 0 || dBdy.size() == N);
00433 #ifdef NDEBUG
00434 if (dBdy.size() == N) {
00435 unsigned int j;
00436 for (j = 0; j < N; j++) {
00437 assert (dBdy[i].size1() == N && dBdy[i].size2() == W);
00438 }
00439 }
00440 #endif
00441
00442 if (dBdy.size() > 0) {
00443 aux::vector b(N);
00444 b.clear();
00445 for (i = 0; i < N; i++) {
00446 ublas::axpy_prod(dBdy[i], row(B,i), b, false);
00447 }
00448 noalias(a) += 0.5 * b;
00449 }
00450 ublas::axpy_prod(B, sde->dWf.top() / delta, a, false);
00451 }
00452 aux::vectorToArray(a, dydt);
00453
00454 return GSL_SUCCESS;
00455 }
00456
00457 #endif
00458