CMS 3D CMS Logo

List of all members | Public Member Functions | Private Member Functions | Private Attributes
GenericHouseholder Class Reference

#include <GenericHouseholder.h>

Public Member Functions

 GenericHouseholder (bool normalise=false)
 
std::vector< float > iterate (const std::vector< std::vector< float > > &eventMatrix, const std::vector< float > &energyVector, const int nIter)
 run the Householder Algorithm several times (nIter). Returns the final vector of calibration coefficients. More...
 
std::vector< float > iterate (const std::vector< std::vector< float > > &eventMatrix, const std::vector< float > &energyVector)
 run the Householder Algorithm. Returns the vector of calibration coefficients. More...
 
 ~GenericHouseholder ()
 Destructor. More...
 

Private Member Functions

bool decompose (const int m, const int n, std::vector< std::vector< float > > &qr, std::vector< float > &alpha, std::vector< int > &pivot)
 
void solve (int m, int n, const std::vector< std::vector< float > > &qr, const std::vector< float > &alpha, const std::vector< int > &pivot, std::vector< float > &r, std::vector< float > &y)
 

Private Attributes

bool normaliseFlag
 

Detailed Description

Generic implementation of the QR decomposition of a matrix using Householder transformation

Author
Lorenzo Agostino, R.Ofierzynski, CERN

Definition at line 13 of file GenericHouseholder.h.

Constructor & Destructor Documentation

◆ GenericHouseholder()

GenericHouseholder::GenericHouseholder ( bool  normalise = false)

Default constructor CAVEAT: use normalise = true only if you know what you're doing!

Definition at line 11 of file GenericHouseholder.cc.

11 : normaliseFlag(normalise) {}

◆ ~GenericHouseholder()

GenericHouseholder::~GenericHouseholder ( )

Destructor.

Definition at line 13 of file GenericHouseholder.cc.

13 {}

Member Function Documentation

◆ decompose()

bool GenericHouseholder::decompose ( const int  m,
const int  n,
std::vector< std::vector< float > > &  qr,
std::vector< float > &  alpha,
std::vector< int > &  pivot 
)
private

make decomposition input: m=number of events, n=number of channels, qr=event matrix output: qr = new event matrix, alpha, pivot returns a boolean value, true if decomposition worked, false if it didn't

Definition at line 188 of file GenericHouseholder.cc.

References alpha, HLT_2022v15_cff::beta, gather_cfg::cout, mps_fire::i, dqmiolumiharvest::j, dqmdumpme::k, visualization-live-secondInstance_cfg::m, dqmiodumpmetadata::n, mathSSE::sqrt(), and y.

Referenced by iterate().

192  {
193  int i, j, jbar, k;
194  float beta, sigma, alphak, qrkk;
195  std::vector<float> y(n);
196  std::vector<float> sum(n);
197 
198  std::cout << "Householder::decompose() started" << std::endl;
199 
200  for (j = 0; j < n; j++) {
201  // jth column sum
202 
203  sum[j] = 0.;
204  for (i = 0; i < m; i++)
205  // std::cout << "0: qr[i][j]" << qr[i][j] << " i = " << i << " j = " << j << std::endl;
206  sum[j] += qr[i][j] * qr[i][j];
207 
208  pivot[j] = j;
209  }
210 
211  for (k = 0; k < n; k++) {
212  // kth Householder transformation
213 
214  sigma = sum[k];
215  jbar = k;
216 
217  for (j = k + 1; j < n; j++) {
218  if (sigma < sum[j]) {
219  sigma = sum[j];
220  jbar = j;
221  }
222  }
223 
224  if (jbar != k) {
225  // column interchange
226  i = pivot[k];
227  pivot[k] = pivot[jbar];
228  pivot[jbar] = i;
229  sum[jbar] = sum[k];
230  sum[k] = sigma;
231 
232  for (i = 0; i < m; i++) {
233  sigma = qr[i][k];
234  qr[i][k] = qr[i][jbar];
235  // std::cout << "A: qr[i][k]" << qr[i][k] << " i = " << i << " k = " << k << std::endl;
236  qr[i][jbar] = sigma;
237  // std::cout << "B: qr[i][jbar]" << qr[i][k] << " i = " << i << " jbar = " << jbar << std::endl;
238  }
239  } // end column interchange
240 
241  sigma = 0.;
242  for (i = k; i < m; i++) {
243  sigma += qr[i][k] * qr[i][k];
244  // std::cout << "C: qr[i][k]" << qr[i][k] << " i = " << i << " k = " << k << std::endl;
245  }
246 
247  if (sigma == 0.) {
248  std::cout << "Householder::decompose() failed" << std::endl;
249  return false;
250  }
251 
252  qrkk = qr[k][k];
253 
254  if (qrkk < 0.)
255  alpha[k] = sqrt(sigma);
256  else
257  alpha[k] = sqrt(sigma) * (-1.);
258  alphak = alpha[k];
259 
260  beta = 1 / (sigma - qrkk * alphak);
261  qr[k][k] = qrkk - alphak;
262 
263  for (j = k + 1; j < n; j++) {
264  y[j] = 0.;
265  for (i = k; i < m; i++)
266  y[j] += qr[i][k] * qr[i][j];
267  y[j] *= beta;
268  }
269 
270  for (j = k + 1; j < n; j++) {
271  for (i = k; i < m; i++) {
272  qr[i][j] -= qr[i][k] * y[j];
273  sum[j] -= qr[k][j] * qr[k][j];
274  }
275  }
276  } // end of kth householder transformation
277 
278  std::cout << "Householder::decompose() finished" << std::endl;
279 
280  return true;
281 }
float alpha
Definition: AMPTWrapper.h:105
T sqrt(T t)
Definition: SSEVec.h:19

◆ iterate() [1/2]

std::vector< float > GenericHouseholder::iterate ( const std::vector< std::vector< float > > &  eventMatrix,
const std::vector< float > &  energyVector,
const int  nIter 
)

run the Householder Algorithm several times (nIter). Returns the final vector of calibration coefficients.

Definition at line 15 of file GenericHouseholder.cc.

References mps_fire::i.

17  {
18  std::vector<float> solution;
19  std::vector<float> theCalibVector(energyVector.size(), 1.);
20  std::vector<std::vector<float> > myEventMatrix(eventMatrix);
21  int Nevents = eventMatrix.size(); // Number of events to calibrate with
22  int Nchannels = eventMatrix[0].size(); // Number of channel coefficients
23 
24  // Iterate the correction
25  for (int iter = 1; iter <= nIter; iter++) {
26  // make one iteration
27  solution = iterate(myEventMatrix, energyVector);
28 
29  if (solution.empty())
30  return solution;
31  // R.O.: or throw an exception, what's the standard CMS way ?
32 
33  // re-calibrate eventMatrix with solution
34  for (int i = 0; i < Nchannels; i++) {
35  for (int ievent = 0; ievent < Nevents; ievent++) {
36  myEventMatrix[ievent][i] *= solution[i];
37  }
38  // save solution into theCalibVector
39  theCalibVector[i] *= solution[i];
40  }
41 
42  } // end iterate the correction
43 
44  return theCalibVector;
45 }
std::vector< float > iterate(const std::vector< std::vector< float > > &eventMatrix, const std::vector< float > &energyVector, const int nIter)
run the Householder Algorithm several times (nIter). Returns the final vector of calibration coeffici...

◆ iterate() [2/2]

std::vector< float > GenericHouseholder::iterate ( const std::vector< std::vector< float > > &  eventMatrix,
const std::vector< float > &  energyVector 
)

run the Householder Algorithm. Returns the vector of calibration coefficients.

Definition at line 47 of file GenericHouseholder.cc.

References A, alpha, gather_cfg::cout, decompose(), MillePedeFileConverter_cfg::e, mps_fire::i, dqmiolumiharvest::j, visualization-live-secondInstance_cfg::m, dqmiodumpmetadata::n, normaliseFlag, alignCSCRings::r, and solve().

48  {
49  // An implementation of the Householder in-situ calibration algorithm
50  // (Least squares minimisation of residual R=b-Ax, with QR decomposition of A)
51  // A: matrix of channel response for all calib events
52  // x: vector of channel calibration coefficients
53  // b: vector of energies
54  // adapted from the original code by Matt Probert 9/08/01.
55 
56  std::vector<float> solution;
57 
58  unsigned int m = eventMatrix.size(); // Number of events to calibrate with
59  unsigned int n = eventMatrix[0].size(); // Number of channel coefficients to optimize
60 
61  std::cout << "Householder::runIter(): starting calibration optimization:" << std::endl;
62  std::cout << " Events:" << m << ", channels: " << n << std::endl;
63 
64  // Sanity check
65  if (m != energyVector.size()) {
66  std::cout << "Householder::runIter(): matrix dimensions non-conformant. " << std::endl;
67  std::cout << " energyVector.size()=" << energyVector.size() << std::endl;
68  std::cout << " eventMatrix[0].size()=" << eventMatrix[0].size() << std::endl;
69  std::cout << " ****************** ERROR *********************" << std::endl;
70  return solution; // empty vector
71  }
72 
73  // Reserve workspace
74  float e25p;
75  unsigned int i, j;
76  std::vector<std::vector<float> > A(eventMatrix);
77  std::vector<float> energies(energyVector);
78 
79  float normalisation = 0.;
80 
81  // Normalise if normaliseFlag is set
82  if (normaliseFlag) {
83  std::cout << "Householder::iterate(): Normalising event data" << std::endl;
84  std::cout << " WARNING: assuming 5x5 filtering has already been done" << std::endl;
85 
86  for (i = 0; i < m; i++) {
87  e25p = 0.;
88  for (j = 0; j < n; j++) {
89  e25p += eventMatrix[i][j]; // lorenzo -> trying to use ESetup which already performs calibs on rechits
90  }
91  e25p /= energyVector[i];
92  normalisation += e25p; // SUM e25p for all events
93  }
94  normalisation /= m;
95  std::cout << " Normalisation = " << normalisation << std::endl;
96 
97  for (i = 0; i < energies.size(); ++i)
98  energies[i] *= normalisation;
99  }
100 
101  // This is where the work goes on...
102  // matrix decomposition
103  std::vector<std::vector<float> > Acopy(A);
104  std::vector<float> alpha(n);
105  std::vector<int> pivot(n);
106  if (!decompose(m, n, A, alpha, pivot)) {
107  std::cout << "Householder::runIter(): Failed: Singular condition in decomposition." << std::endl;
108  std::cout << "***************** PROBLEM in DECOMPOSITION *************************" << std::endl;
109  return solution; // empty vector
110  }
111 
112  /* DBL_EPSILON: Difference between 1.0 and the minimum float greater than 1.0 */
113  float etasqr = DBL_EPSILON * DBL_EPSILON;
114  std::cout << "LOOK at DBL_EPSILON :" << DBL_EPSILON << std::endl;
115 
116  std::vector<float> r(energies); // copy energies vector
117  std::vector<float> e(n);
118 
119  // apply transformations to rhs - find solution vector
120  solution.assign(n, 0.);
121  solve(m, n, A, alpha, pivot, r, solution);
122 
123  // compute residual vector r
124  for (i = 0; i < m; i++) {
125  r[i] = energies[i];
126  for (j = 0; j < n; j++)
127  r[i] -= Acopy[i][j] * solution[j];
128  }
129  // compute first correction vector e
130  solve(m, n, A, alpha, pivot, r, e);
131 
132  float normy0 = 0.;
133  float norme1 = 0.;
134  float norme0;
135 
136  for (i = 0; i < n; i++) {
137  normy0 += solution[i] * solution[i];
138  norme1 += e[i] * e[i];
139  }
140 
141  std::cout << "Householder::runIter(): applying first correction" << std::endl;
142  std::cout << " normy0 = " << normy0 << std::endl;
143  std::cout << " norme1 = " << norme1 << std::endl;
144 
145  // not attempt at obtaining the solution is made unless the norm of the first
146  // correction is significantly smaller than the norm of the initial solution
147  if (norme1 > (0.0625 * normy0)) {
148  std::cout << "Householder::runIter(): first correction is too large. Failed." << std::endl;
149  }
150 
151  // improve the solution
152  for (i = 0; i < n; i++)
153  solution[i] += e[i];
154 
155  std::cout << "Householder::runIter(): improving solution...." << std::endl;
156 
157  // only continue iteration if the correction was significant
158  while (norme1 > (etasqr * normy0)) {
159  std::cout << "Householder::runIter(): norme1 = " << norme1 << std::endl;
160 
161  for (i = 0; i < m; i++) {
162  r[i] = energies[i];
163  for (j = 0; j < n; j++)
164  r[i] -= Acopy[i][j] * solution[j];
165  }
166 
167  // compute next correction vector
168  solve(m, n, A, alpha, pivot, r, e);
169 
170  norme0 = norme1;
171  norme1 = 0.;
172  for (i = 0; i < n; i++)
173  norme1 += e[i] * e[i];
174 
175  // terminate iteration if the norm of the new correction failed to decrease
176  // significantly compared to the norm of the previous correction
177  if (norme1 > (0.0625 * norme0))
178  break;
179 
180  // apply correction vector
181  for (i = 0; i < n; i++)
182  solution[i] += e[i];
183  }
184 
185  return solution;
186 }
float alpha
Definition: AMPTWrapper.h:105
bool decompose(const int m, const int n, std::vector< std::vector< float > > &qr, std::vector< float > &alpha, std::vector< int > &pivot)
void solve(int m, int n, const std::vector< std::vector< float > > &qr, const std::vector< float > &alpha, const std::vector< int > &pivot, std::vector< float > &r, std::vector< float > &y)
Definition: APVGainStruct.h:7

◆ solve()

void GenericHouseholder::solve ( int  m,
int  n,
const std::vector< std::vector< float > > &  qr,
const std::vector< float > &  alpha,
const std::vector< int > &  pivot,
std::vector< float > &  r,
std::vector< float > &  y 
)
private

Apply transformations to rhs output: r = ?, y = solution

Definition at line 283 of file GenericHouseholder.cc.

References alpha, gather_cfg::cout, CustomPhysics_cfi::gamma, mps_fire::i, dqmiolumiharvest::j, visualization-live-secondInstance_cfg::m, dqmiodumpmetadata::n, alignCSCRings::r, y, and z.

Referenced by iterate().

289  {
290  std::vector<float> z(n, 0.);
291 
292  float gamma;
293  int i, j;
294 
295  std::cout << "Householder::solve() begin" << std::endl;
296 
297  for (j = 0; j < n; j++) {
298  // apply jth transformation to the right hand side
299  gamma = 0.;
300  for (i = j; i < m; i++)
301  gamma += qr[i][j] * r[i];
302  gamma /= (alpha[j] * qr[j][j]);
303 
304  for (i = j; i < m; i++)
305  r[i] += gamma * qr[i][j];
306  }
307 
308  // std::cout<<"OK1:"<<std::endl;
309  z[n - 1] = r[n - 1] / alpha[n - 1];
310  // std::cout<<"OK2:"<<std::endl;
311 
312  for (i = n - 2; i >= 0; i--) {
313  z[i] = r[i];
314  for (j = i + 1; j < n; j++)
315  z[i] -= qr[i][j] * z[j];
316  z[i] /= alpha[i];
317  }
318  // std::cout<<"OK3:"<<std::endl;
319 
320  for (i = 0; i < n; i++)
321  y[pivot[i]] = z[i];
322 
323  std::cout << "Householder::solve() finished." << std::endl;
324 }
float alpha
Definition: AMPTWrapper.h:105

Member Data Documentation

◆ normaliseFlag

bool GenericHouseholder::normaliseFlag
private

Definition at line 52 of file GenericHouseholder.h.

Referenced by iterate().