MUQ  0.4.3
MaternKernel.cpp
Go to the documentation of this file.
2 
4 
6 
7 
10 
11 #include "MUQ/Modeling/LinearSDE.h"
12 
13 
14 #include <unsupported/Eigen/Polynomials>
15 #include <Eigen/SparseCore>
16 
17 #include <boost/property_tree/ptree.hpp>
18 
19 using namespace muq::Approximation;
20 
21 
22 
24  std::vector<unsigned> dimInds,
25  double sigma2In,
26  double lengthIn,
27  double nuIn,
28  Eigen::Vector2d sigmaBounds,
29  Eigen::Vector2d lengthBounds) : KernelImpl<MaternKernel>(dimIn, dimInds, 1, 2),
30  nu(nuIn),
31  scale(boost::math::tgamma(nuIn+0.5)/boost::math::tgamma(2.0*nuIn)),
32  weights(BuildWeights(nu-0.5))
33 {
34  CheckNu();
35 
36  paramBounds.resize(2,2);
37  paramBounds(0,0) = sigmaBounds(0);
38  paramBounds(1,0) = sigmaBounds(1);
39 
40  paramBounds(0,1) = lengthBounds(0);
41  paramBounds(1,1) = lengthBounds(1);
42 
43  cachedParams.resize(2);
44  cachedParams(0) = sigma2In;
45  cachedParams(1) = lengthIn;
46 };
47 
49  double sigma2In,
50  double lengthIn,
51  double nuIn,
52  Eigen::Vector2d sigmaBounds,
53  Eigen::Vector2d lengthBounds) : KernelImpl<MaternKernel>(dimIn, 1, 2),
54  nu(nuIn),
55  scale(boost::math::tgamma(nuIn+0.5)/boost::math::tgamma(2.0*nuIn)),
56  weights(BuildWeights(nu-0.5))
57 {
58  CheckNu();
59 
60  paramBounds.resize(2,2);
61  paramBounds(0,0) = sigmaBounds(0);
62  paramBounds(1,0) = sigmaBounds(1);
63 
64  paramBounds(0,1) = lengthBounds(0);
65  paramBounds(1,1) = lengthBounds(1);
66 
67  cachedParams.resize(2);
68  cachedParams(0) = sigma2In;
69  cachedParams(1) = lengthIn;
70 };
71 
72 
73 void MaternKernel::CheckNu() const{
74 
75  if(nu<=0)
76  throw std::invalid_argument("The value of nu must be greater than 0.");
77 
78  if((std::round(nu-0.5)-(nu-0.5)) > 4.0*std::numeric_limits<double>::epsilon())
79  throw std::invalid_argument("The value of nu must take the form nu=i-0.5 for a positive integer i.");
80 
81 };
82 
83 
84 std::tuple<std::shared_ptr<muq::Modeling::LinearSDE>, std::shared_ptr<muq::Modeling::LinearOperator>, Eigen::MatrixXd> MaternKernel::GetStateSpace(boost::property_tree::ptree sdeOptions) const
85 {
86  double sigma2 = cachedParams(0);
87  double length = cachedParams(1);
88  int p = nu-0.5;
89 
90  double lambda = sqrt(2.0*nu)/length;
91 
92  double q = 2.0*sigma2*boost::math::constants::root_pi<double>() * std::pow(lambda, 2*p+1) * tgamma(p+1) / tgamma(p+0.5);
93 
94  Eigen::VectorXd roots = -lambda*Eigen::VectorXd::Ones(p+1);
95  Eigen::VectorXd poly;
96 
97  Eigen::roots_to_monicPolynomial( roots, poly );
98 
99  poly = poly.head(poly.size()-1).eval();
100 
101  std::shared_ptr<muq::Modeling::LinearOperator> F = std::make_shared<muq::Modeling::CompanionMatrix>(-1.0*poly);
102 
103  std::vector<Eigen::Triplet<double>> Lcoeffs;
104  Lcoeffs.push_back(Eigen::Triplet<double>(poly.size()-1,0,1.0));
105 
106  Eigen::SparseMatrix<double> Lmat(poly.size(), 1);
107  Lmat.setFromTriplets(Lcoeffs.begin(), Lcoeffs.end());
108 
109  auto L = muq::Modeling::LinearOperator::Create(Lmat);
110 
111  Eigen::MatrixXd Q(1,1);
112  Q(0,0) = q;
113 
114  // Set up the stochastic differential equation
115  auto sde = std::make_shared<muq::Modeling::LinearSDE>(F, L, Q, sdeOptions);
116 
117 
118  // Define the observation operator, which is just (1,0,...,0) in this case
119  std::vector<Eigen::Triplet<double>> Hcoeffs;
120  Hcoeffs.push_back(Eigen::Triplet<double>(0,0,1.0));
121 
122  Eigen::SparseMatrix<double> Hmat(1,poly.size());
123  Hmat.setFromTriplets(Hcoeffs.begin(), Hcoeffs.end());
124 
125  std::shared_ptr<muq::Modeling::LinearOperator> H = muq::Modeling::LinearOperator::Create(Hmat);
126 
127  // Solve the continuous time Lyapunov equation to find the stationary covariance
128  Q = L->Apply(L->Apply(q*Eigen::VectorXd::Ones(1)).transpose());
129 
130  Eigen::MatrixXd Pinf = muq::Modeling::LyapunovSolver<double>().compute(F->GetMatrix().transpose(), Q).matrixX().real();
131 
132  return std::make_tuple(sde, H, Pinf);
133 }
134 
135 
136 Eigen::VectorXd MaternKernel::BuildWeights(int p)
137 {
138  Eigen::VectorXd output(p+1);
139  for(int i=0; i<=p; ++i){
140 
141  if(i<p){
142  output(i) = static_cast<double>(Factorial(p+i))/(static_cast<double>(Factorial(i)*Factorial(p-i)));
143  }else{
144  output(i) = static_cast<double>(Factorial(p+i)) / static_cast<double>(Factorial(i));
145  }
146  }
147  return output;
148 }
Eigen::VectorXd cachedParams
Definition: KernelBase.h:156
Base class in CRTP pattern for covariance kernels.
Definition: KernelImpl.h:26
static Eigen::VectorXd BuildWeights(int p)
virtual std::tuple< std::shared_ptr< muq::Modeling::LinearSDE >, std::shared_ptr< muq::Modeling::LinearOperator >, Eigen::MatrixXd > GetStateSpace(boost::property_tree::ptree sdeOptions=boost::property_tree::ptree()) const override
Returns a state space representation of the covariance kernel.
MaternKernel(unsigned dimIn, std::vector< unsigned > dimInds, double sigma2In, double lengthIn, double nuIn)
Definition: MaternKernel.h:38
ComplexMatrixType const & matrixX() const
LyapunovSolver & compute(MatrixType const &A, MatrixType const &C)