Belle II Software  release-05-02-19
MultivariateNormalGenerator.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2015 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Martin Ritter *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <framework/utilities/MultivariateNormalGenerator.h>
12 #include <framework/logging/Logger.h>
13 
14 using namespace Belle2;
15 
17 {
18  m_mean.resize(0);
19  m_transform.resize(0, 0);
20 }
21 
22 bool MultivariateNormalGenerator::setMeanCov(int n, const double* mean, const double* cov)
23 {
24  Eigen::VectorXd emean(n);
25  Eigen::MatrixXd ecov(n, n);
26  //Fill the vector and matrix from the buffers in row major layout
27  for (int i = 0; i < n; ++i) {
28  emean[i] = mean[i];
29  for (int j = 0; j < n; ++j) {
30  ecov(i, j) = cov[i * n + j];
31  }
32  }
33  //And delegate to the correct function
34  return setMeanCov(emean, ecov);
35 }
36 
37 
38 bool MultivariateNormalGenerator::setMeanCov(const Eigen::VectorXd& mean, const Eigen::MatrixXd& cov)
39 {
40  reset();
41  if (mean.rows() != cov.rows()) {
42  B2ERROR("Mean values and covariance matrix need to be of the same dimension");
43  return false;
44  }
45  if (cov.rows() != cov.cols()) {
46  B2ERROR("Covariance matrix needs to be a square matrix");
47  return false;
48  }
49 
50  // The usual way to calulate multivariate normal distributed values is to use
51  // the cholesky decomposition C = ll' and then calculate y = mean + l * x
52  // where x is a vector of standard normal distributed values. However this
53  // only works for positive definite matrices so we use the LDLT composition
54  // which gives us C = P'LDL'P and we compute L=P'Lsqrt(D) to get the same
55  // result but in a more robust way which works also for semi-definite
56  // matrices
57  auto ldlt = cov.ldlt();
58  if (ldlt.info() != Eigen::Success) {
59  B2ERROR("Cannot compute LDLT decomposition of covariance "
60  "matrix, maybe not positive semi-definite?");
61  return false;
62  }
63  Eigen::MatrixXd L = ldlt.matrixL();
64  Eigen::MatrixXd D = ldlt.vectorD().asDiagonal();
65  if (D.minCoeff() < 0) {
66  B2ERROR("MultivariateNormalGenerator: Negative values when computing LDL^T "
67  "decomposition, cannot compute M=AA^T, resulting random numbers "
68  "will not be correct");
69  return false;
70  }
71  auto P = ldlt.transpositionsP().transpose();
72  m_transform = P * L * D.cwiseSqrt();
73  //And save the mean values
74  m_mean = mean;
75  return true;
76 }
77 
Belle2::MultivariateNormalGenerator::m_mean
Eigen::VectorXd m_mean
Member to store the mean values of the distribution.
Definition: MultivariateNormalGenerator.h:179
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::MultivariateNormalGenerator::m_transform
Eigen::MatrixXd m_transform
Member to store the transformation matrix for standard normal distributed random values.
Definition: MultivariateNormalGenerator.h:182
Belle2::MultivariateNormalGenerator::setMeanCov
bool setMeanCov(int n, const double *mean, const double *cov)
set the mean and covariance for the distribution with array interface: mean and covariance are passed...
Definition: MultivariateNormalGenerator.cc:22
Belle2::MultivariateNormalGenerator::reset
void reset()
reset the generator setting the size to 0.
Definition: MultivariateNormalGenerator.cc:16