Belle II Software development
DecorrelationMatrix.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
9#pragma once
10
11#include <tracking/trackFindingVXD/filterTools/DecorrelationMatrixHelper.h>
12
13#include <Eigen/Core>
14#include <Eigen/Eigenvalues>
15
16#include <array>
17#include <vector>
18#include <string>
19#include <sstream>
20#include <limits> // needed for getting full precision of doubles for printing
21#include <iomanip>
22
23namespace Belle2 {
35 template<size_t Ndims>
37 public:
39 using MatrixT = Eigen::Matrix<double, Ndims, Ndims, Eigen::RowMajor>;
40
42 explicit DecorrelationMatrix(const MatrixT& matrix = MatrixT::Identity()) : m_matrix(matrix) { }
43
45 DecorrelationMatrix(const DecorrelationMatrix& matrix) = default;
46
49
50 const MatrixT& getMatrix() const { return m_matrix; }
58 void calculateDecorrMatrix(std::array<std::vector<double>, Ndims> inputData, bool normalise = true);
59
60
62 void calculateDecorrMatrix(const MatrixT& covMatrix, bool normalise = true);
63
65 std::vector<double> decorrelate(const std::vector<double>& inputVec) const;
66
68 std::vector<double> decorrelate(const std::array<double, Ndims>& inputs) const;
69
73 std::array<std::vector<double>, Ndims> decorrelate(const std::array<std::vector<double>, Ndims>& inputMat) const;
74
78 std::string print() const;
79
86 bool readFromStream(std::istream& is);
87
88 private:
92 };
93
94
95 // ======================================== IMPLEMENTATION ========================================
96
97 template<size_t Ndims>
98 void DecorrelationMatrix<Ndims>::calculateDecorrMatrix(std::array<std::vector<double>, Ndims> inputData, bool normalise)
99 {
100 calculateDecorrMatrix(calculateCovMatrix(inputData), normalise);
101 }
102
103 // Silence Doxygen which is complaining that "no matching class member found for"
104 // But there should be a better way that I just don't know of / find
106 template<size_t Ndims>
108 {
109 // make an eigen decomposition of the covariance matrix to define the transformation matrix
110 Eigen::SelfAdjointEigenSolver<MatrixT> eigenSolver(covMatrix);
111 const MatrixT U = eigenSolver.eigenvectors();
112
113 if (normalise) {
114 // numerically better (faster hopefully) to not invert a full matrix but to calculate the diagonal elements of the
115 // (diagonal) matrix containing the eigenvalues used for normalization
116 const MatrixT D = eigenSolver.eigenvalues().cwiseSqrt().cwiseInverse().asDiagonal();
117 m_matrix = U * D;
118 } else {
119 m_matrix = U;
120 }
121 }
123
124 template<size_t Ndims>
125 std::vector<double> DecorrelationMatrix<Ndims>::decorrelate(const std::vector<double>& inputVec) const
126 {
127 using RVector = Eigen::Matrix<double, 1, Ndims, Eigen::RowMajor>;
128 Eigen::Map<const RVector> input(inputVec.data(), Ndims);
129
130 const RVector transform = input * m_matrix;
131
132 return std::vector<double>(transform.data(), transform.data() + transform.size());
133 }
134
135 template<size_t Ndims>
136 std::vector<double> DecorrelationMatrix<Ndims>::decorrelate(const std::array<double, Ndims>& input) const
137 {
138 return decorrelate(std::vector<double>(input.begin(), input.end()));
139 }
140
141 template<size_t Ndims>
142 std::array<std::vector<double>, Ndims>
143 DecorrelationMatrix<Ndims>::decorrelate(const std::array<std::vector<double>, Ndims>& inputMat) const
144 {
145 using DVector = Eigen::Matrix<double, Eigen::Dynamic, 1, Eigen::ColMajor>;
146 using DMatrix = Eigen::Matrix<double, Eigen::Dynamic, Ndims, Eigen::ColMajor>;
147
148 size_t nSamples = inputMat[0].size();
149 DMatrix dataMatrix(nSamples, Ndims);
150 for (size_t i = 0; i < Ndims; ++i) {
151 dataMatrix.col(i) = Eigen::Map<const DVector>(inputMat[i].data(), inputMat[i].size());
152 }
153
154 DMatrix transform = dataMatrix * m_matrix;
155
156 std::array<std::vector<double>, Ndims> output;
157 for (size_t i = 0; i < Ndims; ++i) {
158 output[i] = std::vector<double>(transform.col(i).data(), transform.col(i).data() + transform.col(i).size());
159 }
160
161 return output;
162 }
163
164 template<size_t Ndims>
166 {
167 std::stringstream sstr{};
168 sstr << std::setprecision(std::numeric_limits<double>::digits10 + 1) << m_matrix; // ensure precision at write-out
169 return sstr.str();
170 }
171
172 template<size_t Ndims>
174 {
175 MatrixT inMat{};
176 using RVector = Eigen::Matrix<double, 1, Ndims, Eigen::RowMajor>; // typedef for row vector
177
178 size_t iRow = 0;
179 while (iRow < Ndims) { // read only as many lines as needed
180 std::string line{};
181 if (is.eof()) return false;
182 std::getline(is, line);
183 if (line.empty()) continue; // skip empty lines
184 std::stringstream lstr(line);
185 std::array<double, Ndims> linevalues;
186 for (double& value : linevalues) { // read only as many values in the line as needed
187 if (lstr.eof()) return false;
188 lstr >> value;
189 }
190 inMat.row(iRow) = Eigen::Map<const RVector>(linevalues.data(), linevalues.size());
191 ++iRow;
192 }
193
194 m_matrix = inMat;
195 return true;
196 }
197
199} // end namespace Belle 2
Class holding a Matrix that can be used to decorrelate input data to Machine Learning classifiers.
DecorrelationMatrix(const MatrixT &matrix=MatrixT::Identity())
default constructor: initializes to identity matrix or to passed matrix
MatrixT m_matrix
internal matrix holding the data
const MatrixT & getMatrix() const
get the currently stored matrix
void calculateDecorrMatrix(const MatrixT &covMatrix, bool normalise=true)
calculate the matrix that can be used to decorrelate the data that yield the passed covariance matrix...
DecorrelationMatrix(const DecorrelationMatrix &matrix)=default
copy constructor
DecorrelationMatrix & operator=(const DecorrelationMatrix &rhs)=default
assignment operator
Eigen::Matrix< double, Ndims, Ndims, Eigen::RowMajor > MatrixT
typedef for consistent type across class
std::vector< double > decorrelate(const std::vector< double > &inputVec) const
"decorrelate" one measurement (i.e.
std::vector< double > decorrelate(const std::array< double, Ndims > &inputs) const
"decorrelate" one measurement (i.e.
const Eigen::Matrix< double, Ndims, Ndims, Eigen::RowMajor > calculateCovMatrix(std::array< std::vector< double >, Ndims > inputData)
calculates the empirical covariance matrix from the inputData.
void calculateDecorrMatrix(std::array< std::vector< double >, Ndims > inputData, bool normalise=true)
calculate the transformation matrix that when applied to the input data yields linearly uncorrelated ...
bool readFromStream(std::istream &is)
read from stream.
std::string print() const
print the matrix to a string.
std::array< std::vector< double >, Ndims > decorrelate(const std::array< std::vector< double >, Ndims > &inputMat) const
decorrelate M measurements (i.e.
Abstract base class for different kinds of events.