Belle II Software development
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
28namespace 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 {
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>
80 static CovarianceMatrix < N1 + N2 > stackBlocks(const CovarianceMatrix<N1>& block1,
81 const CovarianceMatrix<N2>& block2)
82 {
83 CovarianceMatrix < N1 + N2 > result;
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 {
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 {
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,
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,
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,
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,
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 > fromPrecision(const PrecisionMatrix< N > &prec)
Convert precision matrix to covariance matrix - allows for reduced rank.
static void scale(const ParameterVector< N > &scales, CovarianceMatrix< N > &cov)
Scale the covariance inplace by the given factors in each parameter.
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 void transport(const JacobianMatrix< N, N > &jacobian, CovarianceMatrix< N > &cov)
Transport the covariance matrix inplace with the given jacobian matrix.
static PrecisionMatrix< N > fullToPrecision(const CovarianceMatrix< N > &cov)
Convert precision matrix to covariance matrix - assumes full rank.
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 > fromFullPrecision(const PrecisionMatrix< N > &prec)
Convert covariance matrix to precision matrix - assumes full rank.
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 PrecisionMatrix< N > toPrecision(const CovarianceMatrix< N > &cov)
Convert covariance matrix to precision matrix - allows for reduced rank.
static CovarianceMatrix< N > identity()
Constructs an identity 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< 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< 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 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.