indii/ml/sde/StochasticAdaptiveEulerMaruyama.hpp

00001 #ifndef INDII_ML_SDE_STOCHASTICADAPTIVEEULERMARUYAMA_HPP
00002 #define INDII_ML_SDE_STOCHASTICADAPTIVEEULERMARUYAMA_HPP
00003 
00004 #include "StochasticDifferentialModel.hpp"
00005 #include "StochasticNumericalSolver.hpp"
00006 
00007 namespace indii {
00008   namespace ml {
00009     namespace sde {    
00010 /**
00011  * Stochastic Adaptive Euler-Maruyama method for solving a system of
00012  * stochastic differential equations.
00013  *
00014  * @author Lawrence Murray <lawrence@indii.org>
00015  * @version $Rev: 582 $
00016  * @date $Date: 2008-12-15 17:03:50 +0000 (Mon, 15 Dec 2008) $
00017  *
00018  * @param DT Type of the diffusion matrix.
00019  * @param DDT Type of the diffusion partial derivative matrices.
00020  *
00021  * This class numerically solves StochasticDifferentialModel models
00022  * defining a system of stochastic differential equations using an
00023  * Euler-Maruyama scheme. Error is approximated by comparison with two half
00024  * steps, and step size doubled or halved accordingly.
00025  *
00026  * The general usage idiom is as for
00027  * indii::ml::ode::AdaptiveRungeKutta. The class will automatically
00028  * keep track of Wiener process increments.
00029  *
00030  * @todo This class is tightly coupled with the GSL and would benefit from
00031  * greater independence.
00032  */
00033 template <class DT = indii::ml::aux::matrix,
00034     class DDT = indii::ml::aux::zero_matrix>
00035 class StochasticAdaptiveEulerMaruyama :
00036     public indii::ml::sde::StochasticNumericalSolver {
00037 public:
00038   /**
00039    * Constructor.
00040    *
00041    * @param model Model to estimate.
00042    *
00043    * The time is initialised to zero, but the state is uninitialised
00044    * and should be set with setVariable() or setState().
00045    */
00046   StochasticAdaptiveEulerMaruyama(StochasticDifferentialModel<DT,DDT>* model);
00047 
00048   /**
00049    * Constructor.
00050    *
00051    * @param model Model to estimate.
00052    * @param y0 Initial state.
00053    *
00054    * The time is initialised to zero and the state to that given.
00055    */
00056   StochasticAdaptiveEulerMaruyama(StochasticDifferentialModel<DT,DDT>* model,
00057       const indii::ml::aux::vector& y0);
00058 
00059   /**
00060    * Destructor.
00061    */
00062   virtual ~StochasticAdaptiveEulerMaruyama();
00063 
00064   virtual double step(double upper);
00065 
00066   virtual double stepBack(double lower);
00067 
00068   virtual int calculateDerivativesForward(double t, const double y[],
00069       double dydt[]);
00070 
00071   virtual int calculateDerivativesBackward(double t, const double y[],
00072       double dydt[]);
00073 
00074 private:
00075   /**
00076    * Model.
00077    */
00078   StochasticDifferentialModel<DT,DDT>* model;
00079 
00080   /**
00081    * Drift.
00082    */
00083   indii::ml::aux::vector a1;
00084   
00085   /**
00086    * Drift at midpoint.
00087    */
00088   indii::ml::aux::vector a_mid;
00089   
00090   /**
00091    * Diffusion.
00092    */
00093   DT B1;
00094   
00095   /**
00096    * Diffusion at midpoint.
00097    */
00098   DT B_mid;
00099 
00100 };
00101 
00102     }
00103   }
00104 }
00105 
00106 #include "boost/numeric/ublas/operation.hpp"
00107 #include "boost/numeric/ublas/operation_sparse.hpp"
00108 
00109 template <class DT, class DDT>
00110 indii::ml::sde::StochasticAdaptiveEulerMaruyama<DT,DDT>::StochasticAdaptiveEulerMaruyama(
00111     StochasticDifferentialModel<DT,DDT>* model) :
00112     StochasticNumericalSolver(model->getDimensions(),
00113     model->getNoiseDimensions()), model(model),
00114     a1(model->getDimensions()), a_mid(model->getDimensions()),
00115     B1(model->getDimensions(), model->getNoiseDimensions()),
00116     B_mid(model->getDimensions(), model->getNoiseDimensions()) {
00117   setStepType(gsl_odeiv_step_gear1);
00118 }
00119 
00120 template <class DT, class DDT>
00121 indii::ml::sde::StochasticAdaptiveEulerMaruyama<DT,DDT>::StochasticAdaptiveEulerMaruyama(
00122     StochasticDifferentialModel<DT,DDT>* model,
00123     const indii::ml::aux::vector& y0) : StochasticNumericalSolver(y0,
00124     model->getNoiseDimensions()), model(model),
00125     a1(model->getDimensions()), a_mid(model->getDimensions()),
00126     B1(model->getDimensions(), model->getNoiseDimensions()),
00127     B_mid(model->getDimensions(), model->getNoiseDimensions()) {
00128 
00129   /* pre-condition */
00130   assert (y0.size() == model->getDimensions());
00131 
00132   setStepType(gsl_odeiv_step_gear1);
00133 }
00134 
00135 template <class DT, class DDT>
00136 indii::ml::sde::StochasticAdaptiveEulerMaruyama<DT,DDT>::~StochasticAdaptiveEulerMaruyama() {
00137   //
00138 }
00139 
00140 template <class DT, class DDT>
00141 double indii::ml::sde::StochasticAdaptiveEulerMaruyama<DT,DDT>::step(
00142     double upper) {
00143   /* pre-condition */
00144   assert (upper > t);
00145 
00146   const unsigned int N = model->getDimensions();
00147   const unsigned int V = model->getNoiseDimensions();
00148   double ts, ts_new, ts_mid, ts_prev = 0.0;
00149   double h, h_new, h_mid;
00150   double absErr, relErr;
00151   bool stepDecreased, numSound;
00152   
00153   /* see ode_initval/cstd.c for how state struct is laid out */
00154   double* state = (double*)gslControl->state;
00155   absErr = state[0];
00156   relErr = state[1];
00157 
00158   /* make sure step size won't exceed upper bound */
00159   if (maxStepSize > 0.0 && stepSize > maxStepSize) {
00160     stepSize = maxStepSize;
00161   }
00162   ts = t + stepSize;
00163   if (ts > upper) {
00164     ts = upper;
00165   }
00166 
00167   /* stepping variables */
00168   aux::vector y(this->getState());
00169   aux::vector y1(N), y_mid(N), y2(N);
00170   aux::vector dW1(V), dW_mid(V);
00171   aux::vector epsilon(N), delta(N);
00172   unsigned int i;
00173 
00174   /* new sample of Wiener process */
00175   sampleNoise(&ts);
00176   h = ts - t;
00177 
00178   /* full step */
00179   noalias(dW1) = dWf.top();  
00180   model->calculateDrift(t, y, a1);
00181   model->calculateDiffusion(t, y, B1);
00182   noalias(y1) = y + h*a1;
00183   ublas::axpy_prod(B1, dW1, y1, false);
00184 
00185   ts_mid = 0.5*(ts + t);
00186     
00187   stepDecreased = true; // for loop initialisation
00188   numSound = sampleNoise(&ts_mid);
00189   while (stepDecreased && numSound) {
00190     h_mid = ts_mid - t;
00191 
00192     noalias(dW_mid) = dWf.top();
00193     noalias(y_mid) = y + h_mid*a1;
00194     ublas::axpy_prod(B1, dW_mid, y_mid, false);
00195 
00196     model->calculateDrift(t + h_mid, y_mid, a_mid);
00197     model->calculateDiffusion(t + h_mid, y_mid, B_mid);
00198     noalias(y2) = y_mid + h_mid*a_mid;
00199     ublas::axpy_prod(B_mid, dW1-dW_mid, y2, false);
00200 
00201     /* error control */
00202     /* normal case */
00203     for (i = 0; i < N; i++) {
00204       epsilon(i) = fabs(y1(i) - y2(i));
00205       delta(i) = absErr + relErr*fabs(y1(i));
00206     }
00207     stepDecreased = ublas::norm_inf(element_div(epsilon, delta)) > 1.0;
00208     
00209     if (stepDecreased) {
00210       ts_prev = ts;
00211       ts = ts_mid;
00212       h = h_mid;
00213       noalias(dW1) = dW_mid;
00214       noalias(y1) = y_mid;
00215       
00216       ts_mid = 0.5*(ts + t);
00217       numSound = sampleNoise(&ts_mid);
00218     }
00219   }
00220 
00221   /* update proposed step size */
00222   if (ts_prev > 0.0) {
00223     stepSize = ts_prev - t; // better numerically
00224   } else {
00225     stepSize = 2.0*(ts - t);
00226   }
00227 
00228   /* update state */
00229   aux::vectorToArray(y1, this->y); // don't use setState(), clears tf and dWf
00230 
00231   /* update time */
00232   t = ts;
00233 
00234   /* clean up future path */
00235   if (numSound) {
00236     tf.pop(); // half step sample
00237     dWf.pop();
00238   }
00239   
00240   tf.pop(); // full step sample
00241   dWf.pop();
00242 
00243   /* post-condition */
00244   assert (tf.empty() || t < tf.top());
00245   assert (t <= upper);
00246 
00247   return t;
00248 }
00249 
00250 template <class DT, class DDT>
00251 inline double indii::ml::sde::StochasticAdaptiveEulerMaruyama<DT,DDT>::stepBack(
00252     double lower) {
00253   double t = NumericalSolver::stepBack(lower);
00254 
00255   return t;
00256 }
00257 
00258 template <class DT, class DDT>
00259 inline int indii::ml::sde::StochasticAdaptiveEulerMaruyama<DT,DDT>::calculateDerivativesForward(
00260     double ts, const double y[], double dydt[]) {
00261   /* not required by this implementation */
00262   assert (false);
00263   
00264   return GSL_FAILURE;
00265 }
00266 
00267 template <class DT, class DDT>
00268 inline int indii::ml::sde::StochasticAdaptiveEulerMaruyama<DT,DDT>::calculateDerivativesBackward(
00269     double t, const double y[], double dydt[]) {
00270   /* not required by this implementation */
00271   assert (false);
00272   
00273   return GSL_FAILURE;
00274 }
00275 
00276 #endif
00277 

Generated on Wed Dec 17 15:11:57 2008 for dysii Dynamical Systems Library by  doxygen 1.5.3