Belle II Software  release-08-01-10
CovarianceMatrixUtil.h
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 #pragma once
9 
10 #include <tracking/trackFindingCDC/numerics/PrecisionMatrixUtil.h>
11 #include <tracking/trackFindingCDC/numerics/JacobianMatrixUtil.h>
12 
13 #include <tracking/trackFindingCDC/numerics/CovarianceMatrix.h>
14 #include <tracking/trackFindingCDC/numerics/PrecisionMatrix.h>
15 #include <tracking/trackFindingCDC/numerics/JacobianMatrix.h>
16 #include <tracking/trackFindingCDC/numerics/ParameterVector.h>
17 
18 #include <tracking/trackFindingCDC/numerics/EigenView.h>
19 
20 #include <Eigen/Core>
21 #include <Eigen/LU>
22 #include <Eigen/QR>
23 
24 #include <type_traits>
25 #include <cmath>
26 #include <cassert>
27 
28 namespace Belle2 {
33  namespace TrackFindingCDC {
34 
37 
39  template <int N>
41  {
43  }
44 
46  template <int N>
47  static void transport(const JacobianMatrix<N, N>& jacobian, CovarianceMatrix<N>& cov)
48  {
49  mapToEigen(cov) = mapToEigen(jacobian) * mapToEigen(cov) * mapToEigen(jacobian).transpose();
50  }
51 
53  template <int M, int N>
55  const CovarianceMatrix<N>& cov)
56  {
57  CovarianceMatrix<M> result;
58  mapToEigen(result) = mapToEigen(jacobian) * mapToEigen(cov) * mapToEigen(jacobian).transpose();
59  return result;
60  }
61 
63  template <int N>
64  static void scale(const ParameterVector<N>& scales, CovarianceMatrix<N>& cov)
65  {
66  return transport(JacobianMatrixUtil::scale(scales), cov);
67  }
68 
70  template <int N>
72  const CovarianceMatrix<N>& cov)
73  {
74  return transported(JacobianMatrixUtil::scale(scales), cov);
75  }
76 
79  template <int N1, int N2>
81  const CovarianceMatrix<N2>& block2)
82  {
84  mapToEigen(result) << mapToEigen(block1), Eigen::Matrix<double, N1, N2>::Zero(),
85  Eigen::Matrix<double, N2, N1>::Zero(), mapToEigen(block2);
86  return result;
87  }
88 
90  template <class ACovarianceMatrix, int I = 0, int N = 0>
91  static ACovarianceMatrix getSub(const CovarianceMatrix<N>& cov)
92  {
93  constexpr const int M =
94  std::remove_reference_t<decltype(mapToEigen(ACovarianceMatrix()))>::RowsAtCompileTime;
95  return cov.template block<M, M>(I, I);
96  }
97 
99  template <int N>
101  {
103  mapToEigen(cov) = mapToEigen(prec).colPivHouseholderQr().inverse();
104  return cov;
105  }
106 
108  template <int N>
110  {
111  PrecisionMatrix<N> prec;
112  mapToEigen(prec) = mapToEigen(cov).colPivHouseholderQr().inverse();
113  return prec;
114  }
115 
117  template <int N>
119  {
121  mapToEigen(cov) = mapToEigen(prec).inverse();
122  return cov;
123  }
124 
126  template <int N>
128  {
129  PrecisionMatrix<N> prec;
130  mapToEigen(prec) = mapToEigen(cov).inverse();
131  return prec;
132  }
133 
145  template <int N>
146  static double average(const ParameterVector<N>& par1,
147  const CovarianceMatrix<N>& cov1,
148  const ParameterVector<N>& par2,
149  const CovarianceMatrix<N>& cov2,
150  ParameterVector<N>& par,
151  CovarianceMatrix<N>& cov)
152  {
153  PrecisionMatrix<N> precision1 = toPrecision(cov1);
154  PrecisionMatrix<N> precision2 = toPrecision(cov2);
155  PrecisionMatrix<N> precision;
156  double chi2 =
157  PrecisionMatrixUtil::average(par1, precision1, par2, precision2, par, precision);
158  cov = fromPrecision(precision);
159  return chi2;
160  }
161 
176  template <int M, int N1>
177  static double average(const ParameterVector<N1>& par1,
178  const CovarianceMatrix<N1>& cov1,
179  const JacobianMatrix<N1, M>& ambiguity1,
180  const ParameterVector<M>& par2,
181  const CovarianceMatrix<M>& cov2,
182  ParameterVector<M>& par,
183  CovarianceMatrix<M>& cov)
184  {
185  /* Naive implementation */
186  JacobianMatrix<M, M> ambiguity2 = identity<M>();
187  return average(par1, cov1, ambiguity1, par2, cov2, ambiguity2, par, cov);
188 
189  /* Kalman implementation - may be faster */
190  // par = par2;
191  // cov = cov2;
192  // return kalmanUpdate(par1, cov1, ambiguity1, par, cov);
193  }
194 
209  template <int M, int N1, int N2>
210  static double average(const ParameterVector<N1>& par1,
211  const CovarianceMatrix<N1>& cov1,
212  const JacobianMatrix<N1, M>& ambiguity1,
213  const ParameterVector<N2>& par2,
214  const CovarianceMatrix<N2>& cov2,
215  const JacobianMatrix<N2, M>& ambiguity2,
216  ParameterVector<M>& par,
217  CovarianceMatrix<M>& cov)
218  {
219  PrecisionMatrix<N1> precision1 = toPrecision(cov1);
220  PrecisionMatrix<N2> precision2 = toPrecision(cov2);
221  PrecisionMatrix<M> precision;
222  double chi2 = PrecisionMatrixUtil::average(par1,
223  precision1,
224  ambiguity1,
225  par2,
226  precision2,
227  ambiguity2,
228  par,
229  precision);
230  cov = fromPrecision(precision);
231  return chi2;
232  }
233 
248  template <int M, int N1>
249  static double kalmanUpdate(const ParameterVector<N1>& par1,
250  const CovarianceMatrix<N1>& cov1,
251  const JacobianMatrix<N1, M>& ambiguity1,
252  ParameterVector<M>& par2,
253  CovarianceMatrix<M>& cov2)
254  {
255  /* Kalman update - smart version */
256  const auto& ePar1 = mapToEigen(par1);
257  const auto& eCov1 = mapToEigen(cov1);
258  const auto& eAmbiguity1 = mapToEigen(ambiguity1);
259 
260  auto&& ePar2 = mapToEigen(par2);
261  auto&& eCov2 = mapToEigen(cov2);
262 
263  // Apriori residual
264  auto residual = ePar1 - eAmbiguity1 * ePar2;
265  auto residualCov = eCov1 + eAmbiguity1 * eCov2 * eAmbiguity1.transpose();
266  auto residualPrecision = residualCov.inverse();
267 
268  // Chi2 - calculate on the apriori residuals, which is the same value as for the posterior.
269  Eigen::Matrix<double, 1, 1> chi2 = residual.transpose() * residualPrecision * residual;
270 
271  // Update parameters
272  auto kalmanGain = eCov2 * eAmbiguity1.transpose() * residualPrecision;
273  eCov2 -= kalmanGain * eAmbiguity1 * eCov2;
274  ePar2 += kalmanGain * residual;
275 
276  return chi2[0];
277 
278  // Posterior residual - here for reference, should be compiled out.
279  auto postResidual = ePar1 - eAmbiguity1 * ePar2;
280  auto postResidualCov = eCov1 - eAmbiguity1 * eCov2 * eAmbiguity1.transpose();
281  auto postResidualPrecision = postResidualCov.inverse();
282  Eigen::Matrix<double, 1, 1> postChi2 =
283  postResidual.transpose() * postResidualPrecision * postResidual;
284  (void)postChi2;
285  assert(std::fabs(postChi2[0] - chi2[0]) < 1e-8);
286  }
287  };
288 
289  }
291 }
A matrix implementation to be used as an interface typ through out the track finder.
Definition: PlainMatrix.h:40
static PlainMatrix< T, M, N > Identity()
Construct an identity matrix.
Definition: PlainMatrix.h:74
Abstract base class for different kinds of events.
Collection of functions related to covariance matrices.
static CovarianceMatrix< N > scale(const ParameterVector< N > &scales, const CovarianceMatrix< N > &cov)
Return a copy of the covariance scaled by the given factors in each parameter.
static void scale(const ParameterVector< N > &scales, CovarianceMatrix< N > &cov)
Scale the covariance inplace by the given factors in each parameter.
static void transport(const JacobianMatrix< N, N > &jacobian, CovarianceMatrix< N > &cov)
Transport the covariance matrix inplace with the given jacobian matrix.
static CovarianceMatrix< M > transported(const JacobianMatrix< M, N > &jacobian, const CovarianceMatrix< N > &cov)
Return a copy of the covariance matrix transported with the given jacobian matrix.
static double kalmanUpdate(const ParameterVector< N1 > &par1, const CovarianceMatrix< N1 > &cov1, const JacobianMatrix< N1, M > &ambiguity1, ParameterVector< M > &par2, CovarianceMatrix< M > &cov2)
Updates a parameter and its covariance by integrating information from parameter vector in a projecte...
static CovarianceMatrix< N > identity()
Constructs an identity matrix.
static CovarianceMatrix< N > fromPrecision(const PrecisionMatrix< N > &prec)
Convert precision matrix to covariance matrix - allows for reduced rank.
static PrecisionMatrix< N > fullToPrecision(const CovarianceMatrix< N > &cov)
Convert precision matrix to covariance matrix - assumes full rank.
static CovarianceMatrix< N1+N2 > stackBlocks(const CovarianceMatrix< N1 > &block1, const CovarianceMatrix< N2 > &block2)
Combines two covariance matrices by putting them in two blocks on the diagonal of a larger matrix.
static double average(const ParameterVector< N1 > &par1, const CovarianceMatrix< N1 > &cov1, const JacobianMatrix< N1, M > &ambiguity1, const ParameterVector< N2 > &par2, const CovarianceMatrix< N2 > &cov2, const JacobianMatrix< N2, M > &ambiguity2, ParameterVector< M > &par, CovarianceMatrix< M > &cov)
Averages two parameter vectors from a projected space taking into account their respective covariance...
static CovarianceMatrix< N > fromFullPrecision(const PrecisionMatrix< N > &prec)
Convert covariance matrix to precision matrix - assumes full rank.
static double average(const ParameterVector< N > &par1, const CovarianceMatrix< N > &cov1, const ParameterVector< N > &par2, const CovarianceMatrix< N > &cov2, ParameterVector< N > &par, CovarianceMatrix< N > &cov)
Averages two parameter vectors taking into account their respective covariances.
static ACovarianceMatrix getSub(const CovarianceMatrix< N > &cov)
Gets a subcovariance from a covariance matrix.
static double average(const ParameterVector< N1 > &par1, const CovarianceMatrix< N1 > &cov1, const JacobianMatrix< N1, M > &ambiguity1, const ParameterVector< M > &par2, const CovarianceMatrix< M > &cov2, ParameterVector< M > &par, CovarianceMatrix< M > &cov)
Averages two parameter vectors, one being from a projected space, taking into account their respectiv...
static PrecisionMatrix< N > toPrecision(const CovarianceMatrix< N > &cov)
Convert covariance matrix to precision matrix - allows for reduced rank.
static JacobianMatrix< N > scale(const ParameterVector< N > &scales)
Calculates the jacobian matrix for a scaling in each parameter.
static double average(const ParameterVector< N > &parameter1, const PrecisionMatrix< N > &precision1, const ParameterVector< N > &parameter2, const PrecisionMatrix< N > &precision2, ParameterVector< N > &parameter, PrecisionMatrix< N > &precision)
Averages two parameter vectors taking into account their respective precision.