MUQ  0.4.3
Gaussian.cpp
Go to the documentation of this file.
2 
4 
5 using namespace muq::Utilities;
6 using namespace muq::Modeling;
7 
8 Gaussian::Gaussian(unsigned int dim,
9  InputMask extraInputs) : GaussianBase(dim, GetExtraSizes(dim, extraInputs)),
10  mode(ModeFromExtras(extraInputs)),
11  inputTypes(extraInputs),
12  covPrec(Eigen::VectorXd::Ones(dim))
13 {
15 }
16 
17 Gaussian::Gaussian(Eigen::VectorXd const& muIn,
18  InputMask extraInputs) : GaussianBase(muIn, GetExtraSizes(muIn.size(), extraInputs)),
19  mode(ModeFromExtras(extraInputs)),
20  inputTypes(extraInputs),
21  covPrec(Eigen::VectorXd::Ones(muIn.size()))
22 {
24 }
25 
26 
27 Gaussian::Gaussian(Eigen::VectorXd const& muIn,
28  Eigen::MatrixXd const& obj,
29  Gaussian::Mode modeIn,
30  InputMask extraInputs) : GaussianBase(muIn, GetExtraSizes(muIn.size(), extraInputs)),
31  mode(modeIn),
32  inputTypes(extraInputs),
33  covPrec(obj)
34 {
35  CheckInputTypes(extraInputs, mode);
36  assert(mean.rows()==covPrec.rows());
37  if(covPrec.cols()>1)
38  assert(mean.rows()==covPrec.cols());
39 
40  if(covPrec.cols()>1){
41 
42  sqrtCovPrec = covPrec.selfadjointView<Eigen::Lower>().llt();
43  assert(sqrtCovPrec.info()==Eigen::Success);
44  }
46 }
47 
48 void Gaussian::CheckInputTypes(InputMask extraInputs, Mode mode)
49 {
50  if( (((extraInputs & ExtraInputs::DiagCovariance)>0) || ((extraInputs & ExtraInputs::FullCovariance)>0)) && (mode == Mode::Precision))
51  throw std::logic_error("Extra arguments passed to Gaussian constructor do not match the covariance mode.");
52  if( (((extraInputs & ExtraInputs::DiagPrecision)>0) || ((extraInputs & ExtraInputs::FullPrecision)>0)) && (mode == Mode::Covariance))
53  throw std::logic_error("Extra arguments passed to Gaussian constructor do not match the covariance mode.");
54 }
55 
57 {
58  if( ((extraInputs & ExtraInputs::DiagCovariance)>0) || ((extraInputs & ExtraInputs::FullCovariance)>0)){
59  return Gaussian::Mode::Covariance;
60  }else{
61  return Gaussian::Mode::Precision;
62  }
63 }
64 
65 Eigen::VectorXi Gaussian::GetExtraSizes(unsigned dim, InputMask extraInputs)
66 {
67  Eigen::VectorXi output(2);
68  int numExtras = 0;
69 
70  if((extraInputs & ExtraInputs::Mean)>0){
71  output(0) = dim;
72  numExtras++;
73  }
74 
75  if( ((extraInputs & ExtraInputs::DiagCovariance)>0) || ((extraInputs & ExtraInputs::DiagPrecision)>0)){
76  output(numExtras) = dim;
77  numExtras++;
78  }
79 
80 
81  if( ((extraInputs & ExtraInputs::FullCovariance)>0) || ((extraInputs & ExtraInputs::FullPrecision)>0)){
82  assert(numExtras<2);
83  output(numExtras) = dim*dim;
84  numExtras++;
85  }
86 
87  return output.head(numExtras);
88 }
89 
90 
91 Eigen::MatrixXd Gaussian::GetCovariance() const
92 {
93  if(mode==Mode::Covariance){
94  if(covPrec.cols()==1){
95  return covPrec.col(0).asDiagonal();
96  }else{
97  return covPrec;
98  }
99  }else{
100  if(covPrec.cols()==1){
101  return covPrec.col(0).array().inverse().matrix().asDiagonal();
102  }else{
103  return covPrec.selfadjointView<Eigen::Lower>().llt().solve(Eigen::MatrixXd::Identity(mean.rows(),mean.rows()));
104  }
105  }
106 }
107 
108 Eigen::MatrixXd Gaussian::GetPrecision() const
109 {
110  if(mode==Mode::Precision){
111  if(covPrec.cols()==1){
112  return covPrec.col(0).asDiagonal();
113  }else{
114  return covPrec;
115  }
116  }else{
117  if(covPrec.cols()==1){
118  return covPrec.col(0).array().inverse().matrix().asDiagonal();
119  }else{
120  return covPrec.selfadjointView<Eigen::Lower>().llt().solve(Eigen::MatrixXd::Identity(mean.rows(),mean.rows()));
121  }
122  }
123 }
124 
125 
127 
128  if( mode==Gaussian::Mode::Covariance ) {
129  if(covPrec.cols()==1){
130  logDet = covPrec.array().log().sum();
131  }else{
132  // Compute the log determinant of the covariance
133  logDet = 0.0;
134  for(int i=0; i<sqrtCovPrec.rows(); ++i){
135  logDet += std::log( sqrtCovPrec.matrixL()(i,i) );
136  }
137  logDet *= 2.0;
138  }
139  } else if( mode==Gaussian::Mode::Precision ) {
140  if(covPrec.cols()==1){
141  logDet = -covPrec.array().log().sum();
142  }else{
143  // Compute the log determinant of the covariance
144  logDet = 0.0;
145  for(int i=0; i<sqrtCovPrec.rows(); ++i){
146  logDet += std::log( sqrtCovPrec.matrixL()(i,i) );
147  }
148  logDet *= -2.0;
149  }
150  }
151 }
152 
154 {
155  unsigned currInd = 0;
156 
157  if((inputTypes & ExtraInputs::Mean)>0){
158  assert(inputs.at(currInd).get().size() == mean.size());
159  mean = inputs.at(currInd);
160  currInd++;
161  }
162 
163  if(((inputTypes & ExtraInputs::DiagCovariance)>0) || ((inputTypes & ExtraInputs::DiagPrecision)>0)){
164 
165  if(inputs.at(currInd).get().size() != mean.size())
166  throw muq::WrongSizeError("The given diagonal covariance or precision has " + std::to_string(inputs.at(currInd).get().size()) + " components, but " + std::to_string(mean.size()) + " were expected.");
167 
168  covPrec = inputs.at(currInd).get();
169  }else if(((inputTypes & ExtraInputs::FullCovariance)>0) || ((inputTypes & ExtraInputs::FullPrecision)>0)){
170 
171  if(inputs.at(currInd).get().size() != mean.size()*mean.size())
172  throw muq::WrongSizeError("The given covariance or precision has " + std::to_string(inputs.at(currInd).get().size()) + " components, but " + std::to_string(mean.size()*mean.size()) + " were expected.");
173 
174  Eigen::Map<const Eigen::MatrixXd> mat(inputs.at(currInd).get().data(), mean.size(), mean.size());
175  covPrec = mat;
176  sqrtCovPrec = covPrec.selfadjointView<Eigen::Lower>().llt();
177  }
178 
180 }
181 
182 void Gaussian::SetCovariance(Eigen::MatrixXd const& newCov) {
183 
184  mode = Gaussian::Mode::Covariance;
185 
186  assert(newCov.rows() == mean.rows());
187 
188  covPrec = newCov;
189 
190  if(newCov.cols()>1){
191  assert(newCov.cols() == mean.rows());
192  sqrtCovPrec = covPrec.selfadjointView<Eigen::Lower>().llt();
193  }
194 
195  // recompute the scaling constant
197 }
198 
199 void Gaussian::SetPrecision(Eigen::MatrixXd const& newPrec) {
200 
201  mode = Gaussian::Mode::Precision;
202 
203  assert(newPrec.rows() == mean.rows());
204 
205  if(newPrec.cols()>1)
206  assert(newPrec.cols() == mean.rows());
207 
208  covPrec = newPrec;
209  sqrtCovPrec = covPrec.selfadjointView<Eigen::Lower>().llt();
210 
211  // recompute the scaling constant
213 }
214 
215 Eigen::MatrixXd Gaussian::ApplyCovSqrt(Eigen::Ref<const Eigen::MatrixXd> const& x) const
216 {
217  if(mode==Gaussian::Mode::Covariance){
218  if(covPrec.cols()==1){
219  return covPrec.col(0).array().sqrt().matrix().asDiagonal()*x;
220  }else{
221  return sqrtCovPrec.matrixL()*x;
222  }
223  }else{
224  if(covPrec.cols()==1){
225  return covPrec.col(0).array().inverse().sqrt().matrix().asDiagonal() * x;
226  }else{
227  return sqrtCovPrec.matrixL().solve(x);
228  }
229  }
230 }
231 Eigen::MatrixXd Gaussian::ApplyPrecSqrt(Eigen::Ref<const Eigen::MatrixXd> const& x) const
232 {
233  if(mode==Gaussian::Mode::Precision){
234  if(covPrec.cols()==1){
235  return covPrec.col(0).array().sqrt().matrix().asDiagonal()*x;
236  }else{
237  return sqrtCovPrec.matrixL()*x;
238  }
239  }else{
240  if(covPrec.cols()==1){
241  return covPrec.col(0).array().inverse().sqrt().matrix().asDiagonal() * x;
242  }else{
243  return sqrtCovPrec.matrixL().solve(x);
244  }
245  }
246 }
247 
248 Eigen::MatrixXd Gaussian::ApplyCovariance(Eigen::Ref<const Eigen::MatrixXd> const& x) const
249 {
250  if(mode==Gaussian::Mode::Covariance){
251  if(covPrec.cols()==1){
252  return covPrec.col(0).matrix().asDiagonal()*x;
253  }else{
254  return covPrec.selfadjointView<Eigen::Lower>()*x;
255  }
256  }else{
257  if(covPrec.cols()==1){
258  return covPrec.col(0).array().inverse().matrix().asDiagonal() * x;
259  }else{
260  return sqrtCovPrec.solve(x);
261  }
262  }
263 }
264 Eigen::MatrixXd Gaussian::ApplyPrecision(Eigen::Ref<const Eigen::MatrixXd> const& x) const
265 {
266  if(mode==Gaussian::Mode::Covariance){
267  if(covPrec.cols()==1){
268  return covPrec.col(0).array().inverse().matrix().asDiagonal()*x;
269  }else{
270  return sqrtCovPrec.solve(x);
271  }
272  }else{
273  if(covPrec.cols()==1){
274  return covPrec.col(0).asDiagonal() * x;
275  }else{
276  return covPrec.selfadjointView<Eigen::Lower>()*x;
277  }
278  }
279 }
280 
281 
282 std::shared_ptr<Gaussian> Gaussian::Condition(Eigen::MatrixXd const& obsMat,
283  Eigen::VectorXd const& data,
284  Eigen::MatrixXd const& obsCov) const
285 {
286  if(obsMat.cols() != Dimension())
287  throw muq::WrongSizeError("In Gaussian::Condition, the number of columns in the observation matrix (" + std::to_string(obsMat.cols()) + ") does match the distribution dimension (" + std::to_string(Dimension()) + ")");
288  if(obsMat.rows() != data.rows())
289  throw muq::WrongSizeError("In Gaussian::Condition, the number of rows in the observation matrix (" + std::to_string(obsMat.rows()) + ") does match the size of the data (" + std::to_string(data.rows()) + ")");
290  if(obsCov.rows() != data.rows())
291  throw muq::WrongSizeError("In Gaussian::Condition, the length of the data vector (" + std::to_string(data.rows()) + ") does match the size of the observation covariance (" + std::to_string(obsCov.rows()) + ")");
292  if((obsCov.rows() != obsCov.cols()) && (obsCov.cols()!=1))
293  throw muq::WrongSizeError("In Gaussian::Condition, the given observation covariance has size " + std::to_string(obsCov.rows()) + "x" + std::to_string(obsCov.cols()) + " but should be square.");
294 
295  Eigen::MatrixXd HP = ApplyCovariance(obsMat.transpose()).transpose();
296  Eigen::MatrixXd S = obsMat * HP.transpose();
297  if(obsCov.cols()==1){
298  S += obsCov.asDiagonal();
299  }else{
300  S += obsCov;
301  }
302 
303  Eigen::MatrixXd K = S.selfadjointView<Eigen::Lower>().ldlt().solve(HP).transpose();
304 
305  Eigen::VectorXd postMu = mean + K*(data - obsMat*mean);
306  Eigen::MatrixXd postCov = GetCovariance() - K*HP;
307 
308  return std::make_shared<Gaussian>(postMu, postCov);
309 }
Defines an abstract Gaussian class.@seealso Gaussian.
Definition: GaussianBase.h:15
virtual unsigned int Dimension() const
Gaussian::InputMask inputTypes
What form do the extra inputs take? Just the mean, or the mean and covariance?
Definition: Gaussian.h:116
Eigen::MatrixXd GetPrecision() const
Definition: Gaussian.cpp:108
Gaussian::Mode mode
Have we specified the covariance or the precision.
Definition: Gaussian.h:113
void SetCovariance(Eigen::MatrixXd const &newCov)
Set the covariance matrix.
Definition: Gaussian.cpp:182
void SetPrecision(Eigen::MatrixXd const &newPrec)
Set the precision matrix.
Definition: Gaussian.cpp:199
static Gaussian::Mode ModeFromExtras(InputMask extraInputs)
Definition: Gaussian.cpp:56
static void CheckInputTypes(InputMask extraInputs, Mode mode)
Definition: Gaussian.cpp:48
virtual Eigen::MatrixXd ApplyCovSqrt(Eigen::Ref< const Eigen::MatrixXd > const &x) const override
Definition: Gaussian.cpp:215
void ComputeNormalization()
Compute the distribution's scaling constant.
Definition: Gaussian.cpp:126
Eigen::LLT< Eigen::MatrixXd > sqrtCovPrec
Definition: Gaussian.h:122
Eigen::MatrixXd covPrec
Definition: Gaussian.h:119
std::shared_ptr< Gaussian > Condition(Eigen::MatrixXd const &obsMat, Eigen::VectorXd const &data, Eigen::MatrixXd const &obsCov) const
Returns a new Gaussian distribution conditioned on a linear observation.
Definition: Gaussian.cpp:282
static Eigen::VectorXi GetExtraSizes(unsigned dim, InputMask extraInputs)
Definition: Gaussian.cpp:65
Mode
Are we specifying the mean, covariance matrix, or precision matrix.
Definition: Gaussian.h:18
Gaussian(unsigned int dim, InputMask extraInputs=ExtraInputs::None)
Definition: Gaussian.cpp:8
virtual Eigen::MatrixXd ApplyPrecSqrt(Eigen::Ref< const Eigen::MatrixXd > const &x) const override
Definition: Gaussian.cpp:231
double logDet
The log determinant of the covariance matrix.
Definition: Gaussian.h:125
virtual Eigen::MatrixXd ApplyCovariance(Eigen::Ref< const Eigen::MatrixXd > const &x) const override
Definition: Gaussian.cpp:248
virtual Eigen::MatrixXd ApplyPrecision(Eigen::Ref< const Eigen::MatrixXd > const &x) const override
Definition: Gaussian.cpp:264
Eigen::MatrixXd GetCovariance() const
Get the covariance.
Definition: Gaussian.cpp:91
void ResetHyperparameters(ref_vector< Eigen::VectorXd > const &params) override
Definition: Gaussian.cpp:153
Exception to throw when matrices, vectors, or arrays are the wrong size.
Definition: Exceptions.h:58
std::vector< std::reference_wrapper< const T > > ref_vector
A vector of references to something ...
Definition: WorkPiece.h:37
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.h:25172