MUQ  0.4.3
LinearSDE.h
Go to the documentation of this file.
1 #ifndef LINEARSDE_H
2 #define LINEARSDE_H
3 
5 
7 
8 #include <boost/property_tree/ptree.hpp>
9 #include <random>
10 
11 namespace muq
12 {
13 namespace Modeling
14 {
15 
27  class LinearSDE
28  {
29 
30  public:
31 
32  template<typename EigenType1, typename EigenType2>
33  LinearSDE(EigenType1 const& Fin,
34  EigenType2 const& Lin,
35  Eigen::MatrixXd const& Qin,
36  boost::property_tree::ptree options) : LinearSDE(muq::Modeling::LinearOperator::Create(Fin),
37  muq::Modeling::LinearOperator::Create(Lin),
38  Qin,
39  options)
40  {};
41 
42  template<typename Type1, typename Type2>
43  LinearSDE(std::shared_ptr<Type1> Fin,
44  std::shared_ptr<Type2> Lin,
45  Eigen::MatrixXd const& Qin,
46  boost::property_tree::ptree options) : LinearSDE(std::dynamic_pointer_cast<LinearOperator>(Fin),std::dynamic_pointer_cast<LinearOperator>(Lin), Qin, options){};
47 
48 
49  LinearSDE(std::shared_ptr<muq::Modeling::LinearOperator> Fin,
50  std::shared_ptr<muq::Modeling::LinearOperator> Lin,
51  Eigen::MatrixXd const& Qin,
52  boost::property_tree::ptree options);
53 
54 
55  LinearSDE(std::shared_ptr<muq::Modeling::LinearOperator> Fin,
56  boost::property_tree::ptree options);
57 
58 
61  template<typename EigenRefVector>
62  Eigen::VectorXd EvolveState(EigenRefVector const& f0,
63  double T) const
64  {
65  Eigen::VectorXd fnext(f0.size());
66  EvolveState(f0, T, Eigen::Ref<Eigen::VectorXd>(fnext));
67  return fnext;
68  }
69 
70  template<typename EigenRefVector1, typename EigenRefVector2>
71  void EvolveState(EigenRefVector1 const& f0,
72  double T,
73  EigenRefVector2 f) const
74  {
75  f = f0;
76 
77  if(T<std::numeric_limits<double>::epsilon()){
78  return;
79  }
80 
81  const int numTimes = std::ceil(T/dt);
82 
83  Eigen::VectorXd z;
84 
85  // Take all but the last step. The last step might be a partial step
86  for(int i=0; i<numTimes-1; ++i)
87  {
88  if(L){
89  z = sqrt(dt) * (sqrtQ.triangularView<Eigen::Lower>() * muq::Utilities::RandomGenerator::GetNormal(sqrtQ.cols()) ).eval();
90  f += dt*F->Apply(f) + L->Apply( z );
91  }else{
92  f += dt*F->Apply(f);
93  }
94  }
95 
96  // Now take the last step
97  double lastDt = T-(numTimes-1)*dt;
98  if(L){
99  z = sqrt(lastDt) * (sqrtQ.triangularView<Eigen::Lower>() * muq::Utilities::RandomGenerator::GetNormal(sqrtQ.cols())).eval();
100  f += lastDt*F->Apply(f) + L->Apply( z );
101  }else{
102  f += lastDt*F->Apply(f);
103  }
104  }
105 
106 
109  template<typename EigenRefVector, typename EigenRefMatrix>
110  std::pair<Eigen::VectorXd, Eigen::MatrixXd> EvolveDistribution(EigenRefVector const& mu0,
111  EigenRefMatrix const& gamma0,
112  double T) const
113  {
114  Eigen::VectorXd mu(mu0.size());
115  Eigen::MatrixXd cov(gamma0.rows(), gamma0.cols());
116 
117  EvolveDistribution(mu0,gamma0, T, Eigen::Ref<Eigen::VectorXd>(mu), Eigen::Ref<Eigen::MatrixXd>(cov));
118  return std::make_pair(mu,cov);
119  }
120 
121  template<typename EigenRefVector1, typename EigenRefMatrix1, typename EigenRefVector2, typename EigenRefMatrix2>
122  void EvolveDistribution(EigenRefVector1 const& mu0,
123  EigenRefMatrix1 const& gamma0,
124  double T,
125  EigenRefVector2 mu,
126  EigenRefMatrix2 gamma) const
127  {
128 
129  if(mu0.size()!=mu.size()){
130  throw std::runtime_error("In LinearSDE::EvolveDistribution: mu0 and mu have different sizes.");
131  }
132  if((gamma0.rows()!=gamma.rows())||(gamma0.cols()!=gamma.cols())){
133  throw std::runtime_error("In LinearSDE::EvolveDistribution: gamma0 and gamma have different sizes.");
134  }
135 
136  mu = mu0;
137  gamma = gamma0;
138 
139  if(T<std::numeric_limits<double>::epsilon()){
140  return;
141  }
142 
143  const int numTimes = std::ceil(T/dt);
144 
145  // Fourth-Order Stochastic Runge-Kutta method
146  if(integratorType=="SRK4"){
147 
148  Eigen::MatrixXd Fgamma, k1, k2, k3, k4;
149 
150  // Take all but the last step because the last step might be a partial step.
151  for(int i=0; i<numTimes-1; ++i)
152  {
153  k1 = F->Apply(mu);
154  k2 = F->Apply(mu + 0.5*dt*k1);
155  k3 = F->Apply(mu + 0.5*dt*k2);
156  k4 = F->Apply(mu + dt*k3);
157  mu = mu + (dt/6.0)*(k1 + 2.0*k2 + 2.0*k3 + k4);
158 
159  Fgamma = F->Apply(gamma);
160  k1 = Fgamma + Fgamma.transpose() + LQLT;
161  Fgamma = F->Apply(gamma + 0.5*dt*k1);
162  k2 = Fgamma + Fgamma.transpose() + LQLT;
163  Fgamma = F->Apply(gamma + 0.5*dt*k2);
164  k3 = Fgamma + Fgamma.transpose() + LQLT;
165  Fgamma = F->Apply(gamma + dt*k3);
166  k4 = Fgamma + Fgamma.transpose() + LQLT;
167 
168  gamma = gamma + (dt/6.0)*(k1 + 2.0*k2 + 2.0*k3 + k4);
169  }
170 
171  // Take the last step
172  double lastDt = T-(numTimes-1)*dt;
173 
174  k1 = F->Apply(mu);
175  k2 = F->Apply(mu + 0.5*lastDt*k1);
176  k3 = F->Apply(mu + 0.5*lastDt*k2);
177  k4 = F->Apply(mu + lastDt*k3);
178  mu = mu + (lastDt/6.0)*(k1 + 2.0*k2 + 2.0*k3 + k4);
179 
180  Fgamma = F->Apply(gamma);
181  k1 = Fgamma + Fgamma.transpose() + LQLT;
182  Fgamma = F->Apply(gamma + 0.5*lastDt*k1);
183  k2 = Fgamma + Fgamma.transpose() + LQLT;
184  Fgamma = F->Apply(gamma + 0.5*lastDt*k2);
185  k3 = Fgamma + Fgamma.transpose() + LQLT;
186  Fgamma = F->Apply(gamma + lastDt*k3);
187  k4 = Fgamma + Fgamma.transpose() + LQLT;
188 
189  gamma = gamma + (lastDt/6.0)*(k1 + 2.0*k2 + 2.0*k3 + k4);
190 
191  // Euler-Maruyama method
192  }else{
193 
194  // Take all but the last step because the last step might be a partial step.
195  for(int i=0; i<numTimes-1; ++i){
196  mu += dt*F->Apply(mu);
197  gamma += dt*dt*(F->Apply(F->Apply(gamma).transpose().eval()).transpose()) + dt*LQLT;
198  }
199 
200  // Take the last step
201  double lastDt = T-(numTimes-1)*dt;
202 
203  mu += lastDt*F->Apply(mu);
204  gamma += lastDt*lastDt*(F->Apply(F->Apply(gamma).transpose().eval()).transpose()) + lastDt*LQLT;
205 
206  }
207  }
208 
211  template<typename EigenRefVector, typename EigenRefMatrix>
212  std::pair<Eigen::VectorXd, Eigen::MatrixXd> EvolveDistribution(std::pair<EigenRefVector,EigenRefMatrix> const& muCov,
213  double T) const{
214  return EvolveDistribution(muCov.first, muCov.second, T);
215  };
216 
217 
221  std::pair<Eigen::MatrixXd, Eigen::MatrixXd> Discretize(double deltaT);
222 
235  static std::shared_ptr<LinearSDE> Concatenate(std::vector<std::shared_ptr<LinearSDE>> const& sdes,
236  boost::property_tree::ptree options = boost::property_tree::ptree());
237 
238 
240  const int stateDim;
241 
242 
243  std::shared_ptr<muq::Modeling::LinearOperator> GetF() const{return F;};
244  std::shared_ptr<muq::Modeling::LinearOperator> GetL() const{return L;};
245  Eigen::MatrixXd const& GetQ() const{return Q;};
246 
247 
248  protected:
249 
250  void ExtractOptions(boost::property_tree::ptree options);
251 
252  std::shared_ptr<muq::Modeling::LinearOperator> F;
253  std::shared_ptr<muq::Modeling::LinearOperator> L;
254 
255  Eigen::MatrixXd Q;
256  Eigen::MatrixXd sqrtQ;
257 
258  double dt; // time step used in SDE integration
259  std::string integratorType; // Type of integratin to use (either EM for "Euler Maruyama" or "SRK4" for Stochastic Runge Kutta)
260 
261  Eigen::MatrixXd LQLT;
262  };
263 
264 
265 }// namespace Modeling
266 }// namespace muq
267 
268 
269 
270 
271 #endif
Generic linear operator base class.
Defines a linear time invariant stochastic differential equation with Gaussian process noise.
Definition: LinearSDE.h:28
Eigen::MatrixXd Q
Definition: LinearSDE.h:255
LinearSDE(std::shared_ptr< Type1 > Fin, std::shared_ptr< Type2 > Lin, Eigen::MatrixXd const &Qin, boost::property_tree::ptree options)
Definition: LinearSDE.h:43
Eigen::MatrixXd sqrtQ
Definition: LinearSDE.h:256
std::shared_ptr< muq::Modeling::LinearOperator > GetL() const
Definition: LinearSDE.h:244
std::shared_ptr< muq::Modeling::LinearOperator > L
Definition: LinearSDE.h:253
void EvolveState(EigenRefVector1 const &f0, double T, EigenRefVector2 f) const
Definition: LinearSDE.h:71
Eigen::MatrixXd LQLT
Definition: LinearSDE.h:261
void ExtractOptions(boost::property_tree::ptree options)
Definition: LinearSDE.cpp:49
std::shared_ptr< muq::Modeling::LinearOperator > F
Definition: LinearSDE.h:252
Eigen::VectorXd EvolveState(EigenRefVector const &f0, double T) const
Definition: LinearSDE.h:62
std::pair< Eigen::MatrixXd, Eigen::MatrixXd > Discretize(double deltaT)
Definition: LinearSDE.cpp:213
Eigen::MatrixXd const & GetQ() const
Definition: LinearSDE.h:245
static std::shared_ptr< LinearSDE > Concatenate(std::vector< std::shared_ptr< LinearSDE >> const &sdes, boost::property_tree::ptree options=boost::property_tree::ptree())
Combines the states of multiple SDEs into a single monolitch SDE.
Definition: LinearSDE.cpp:180
std::pair< Eigen::VectorXd, Eigen::MatrixXd > EvolveDistribution(std::pair< EigenRefVector, EigenRefMatrix > const &muCov, double T) const
Definition: LinearSDE.h:212
const int stateDim
The dimension of the state variable .
Definition: LinearSDE.h:240
std::shared_ptr< muq::Modeling::LinearOperator > GetF() const
Definition: LinearSDE.h:243
std::pair< Eigen::VectorXd, Eigen::MatrixXd > EvolveDistribution(EigenRefVector const &mu0, EigenRefMatrix const &gamma0, double T) const
Definition: LinearSDE.h:110
void EvolveDistribution(EigenRefVector1 const &mu0, EigenRefMatrix1 const &gamma0, double T, EigenRefVector2 mu, EigenRefMatrix2 gamma) const
Definition: LinearSDE.h:122
std::string integratorType
Definition: LinearSDE.h:259
LinearSDE(EigenType1 const &Fin, EigenType2 const &Lin, Eigen::MatrixXd const &Qin, boost::property_tree::ptree options)
Definition: LinearSDE.h:33