CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
GaussianSumUtilities1D.cc
Go to the documentation of this file.
3 
4 // #include "Utilities/Timing/interface/TimingReport.h"
5 // #include "Utilities/Timing/interface/TimerStack.h"
6 
7 // #include "TROOT.h"
8 // #include "TMath.h"
9 #include "Math/ProbFuncMathCore.h"
10 #include "Math/PdfFuncMathCore.h"
11 #include "Math/QuantFuncMathCore.h"
12 
13 #include <iostream>
14 #include <cmath>
15 
16 #include <map>
17 #include <functional>
18 #include <numeric>
19 #include <algorithm>
20 
21 double GaussianSumUtilities1D::pdf(unsigned int i, double x) const {
22  return weight(i) * gauss(x, mean(i), standardDeviation(i));
23 }
24 
25 double GaussianSumUtilities1D::quantile(const double q) const { return ROOT::Math::gaussian_quantile(q, 1.); }
26 
27 // double
28 // GaussianSumUtilities1D::quantile (const double q) const
29 // {
30 // //
31 // // mean and sigma of highest weight component
32 // //
33 // int iwMax(-1);
34 // float wMax(0.);
35 // for ( unsigned int i=0; i<size(); i++ ) {
36 // if ( weight(i)>wMax ) {
37 // iwMax = i;
38 // wMax = weight(i);
39 // }
40 // }
41 // //
42 // // Find start values: begin with mean and
43 // // go towards f(x)=0 until two points on
44 // // either side are found (assumes monotonously
45 // // increasing function)
46 // //
47 // double x1(mean(iwMax));
48 // double y1(cdf(x1)-q);
49 // double dx = y1>0. ? -standardDeviation(iwMax) : standardDeviation(iwMax);
50 // double x2(x1+dx);
51 // double y2(cdf(x2)-q);
52 // while ( y1*y2>0. ) {
53 // x1 = x2;
54 // y1 = y2;
55 // x2 += dx;
56 // y2 = cdf(x2) - q;
57 // }
58 // //
59 // // now use bisection to find final value
60 // //
61 // double x(0.);
62 // while ( true ) {
63 // // use linear interpolation
64 // x = -(x2*y1-x1*y2)/(y2-y1);
65 // double y = cdf(x) - q;
66 // if ( fabs(y)<1.e-6 ) break;
67 // if ( y*y1>0. ) {
68 // y1 = y;
69 // x1 = x;
70 // }
71 // else {
72 // y2 = y;
73 // x2 = x;
74 // }
75 // }
76 // return x;
77 // }
78 
81  computeMode();
82  return theModeStatus == Valid;
83 }
84 
87  computeMode();
88  return theMode;
89 }
90 
92  // TimerStack tstack;
93  // tstack.benchmark("GSU1D::benchmark",100000);
94  // FastTimerStackPush(tstack,"GaussianSumUtilities1D::computeMode");
96  //
97  // check for "degenerate" states (identical values with vanishing error)
98  //
99  if (theState.variance() < 1.e-14) {
102  return;
103  }
104  //
105  // Use means of individual components as start values.
106  // Sort by value of pdf.
107  //
108  typedef std::multimap<double, int, std::greater<double> > StartMap;
109  StartMap xStart;
110  for (unsigned int i = 0; i < size(); i++) {
111  xStart.insert(std::make_pair(pdf(mean(i)), i));
112  }
113  //
114  // Now try with each start value
115  //
116  int iRes(-1); // index of start component for current estimate
117  double xRes(mean((*xStart.begin()).second)); // current estimate of mode
118  double yRes(-1.); // pdf at current estimate of mode
119  // std::pair<double,double> result(-1.,mean((*xStart.begin()).second));
120  for (StartMap::const_iterator i = xStart.begin(); i != xStart.end(); i++) {
121  //
122  // Convergence radius for a single Gaussian = 1 sigma: don't try
123  // start values within 1 sigma of the current solution
124  //
125  if (theModeStatus == Valid && fabs(mean((*i).second) - mean(iRes)) / standardDeviation(iRes) < 1.)
126  continue;
127  //
128  // If a solution exists: drop as soon as the pdf at
129  // start value drops to < 75% of maximum (try to avoid
130  // unnecessary searches for the mode)
131  //
132  if (theModeStatus == Valid && (*i).first / (*xStart.begin()).first < 0.75)
133  break;
134  //
135  // Try to find mode
136  //
137  double x;
138  double y;
139  bool valid = findMode(x, y, mean((*i).second), standardDeviation((*i).second));
140  //
141  // consider only successful searches
142  //
143  if (valid) { //...
144  //
145  // update result only for significant changes in pdf(solution)
146  //
147  if (yRes < 0. || (y - yRes) / (y + yRes) > 1.e-10) {
148  iRes = (*i).second; // store index
149  theModeStatus = Valid; // update status
150  xRes = x; // current solution
151  yRes = y; // and its pdf value
152  // result = std::make_pair(y,x); // store solution and pdf(solution)
153  }
154  } //...
155  }
156  //
157  // check (existance of) solution
158  //
159  if (theModeStatus == Valid) {
160  //
161  // Construct single Gaussian state with
162  // mean = mode
163  // variance = local variance at mode
164  // weight such that the pdf's of the mixture and the
165  // single state are equal at the mode
166  //
167  double mode = xRes;
168  double varMode = localVariance(mode);
169  double wgtMode = pdf(mode) * sqrt(2 * M_PI * varMode);
170  theMode = SingleGaussianState1D(mode, varMode, wgtMode);
171  } else {
172  //
173  // mode finding failed: set solution to highest component
174  // (alternative would be global mean / variance ..?)
175  //
176  //two many log warnings to actually be useful - comment out
177  //edm::LogWarning("GaussianSumUtilities") << "1D mode calculation failed";
178  // double x = mean();
179  // double y = pdf(x);
180  // result = std::make_pair(y,x);
181  // theMode = SingleGaussianState1D(mean(),variance(),weight());
182  //
183  // look for component with highest value at mean
184  //
185  int icMax(0);
186  double ySqMax(0.);
187  int s = size();
188  for (int ic = 0; ic < s; ++ic) {
189  double w = weight(ic);
190  double ySq = w * w / variance(ic);
191  if (ySq > ySqMax) {
192  icMax = ic;
193  ySqMax = ySq;
194  }
195  }
197  }
198 }
199 
200 bool GaussianSumUtilities1D::findMode(double& xMode, double& yMode, const double& xStart, const double& scale) const {
201  //
202  // try with Newton on (lnPdf)'(x)
203  //
204  double x1(0.);
205  double y1(0.);
207  update(state, xStart);
208 
209  double xmin(xStart - 1. * scale);
210  double xmax(xStart + 1. * scale);
211  //
212  // preset result
213  //
214  bool result(false);
215  xMode = state.x;
216  yMode = state.y;
217  //
218  // Iterate
219  //
220  int nLoop(0);
221  while (nLoop++ < 20) {
222  if (nLoop > 1 && state.yd2 < 0. &&
223  (fabs(state.yd * scale) < 1.e-10 || fabs(state.y - y1) / (state.y + y1) < 1.e-14)) {
224  result = true;
225  break;
226  }
227  if (fabs(state.yd2) < std::numeric_limits<float>::min())
229  double dx = -state.yd / state.yd2;
230  x1 = state.x;
231  y1 = state.y;
232  double x2 = x1 + dx;
233  if (state.yd2 > 0. && (x2 < xmin || x2 > xmax))
234  return false;
235  update(state, x2);
236  }
237  //
238  // result
239  //
240  if (result) {
241  xMode = state.x;
242  yMode = state.y;
243  }
244  return result;
245 }
246 
248  state.x = x;
249 
250  pdfComponents(state.x, state.pdfs);
251  state.y = pdf(state.x, state.pdfs);
252  state.yd = 0;
253  if (state.y > std::numeric_limits<double>::min())
254  state.yd = d1Pdf(state.x, state.pdfs) / state.y;
255  state.yd2 = -state.yd * state.yd;
256  if (state.y > std::numeric_limits<double>::min())
257  state.yd2 += d2Pdf(state.x, state.pdfs) / state.y;
258 }
259 
260 double GaussianSumUtilities1D::pdf(double x) const {
261  double result(0.);
262  size_t s = size();
263  for (unsigned int i = 0; i < s; i++)
264  result += pdf(i, x);
265  return result;
266 }
267 
268 double GaussianSumUtilities1D::cdf(const double& x) const {
269  double result(0.);
270  size_t s = size();
271  for (unsigned int i = 0; i < s; i++)
272  result += weight(i) * gaussInt(x, mean(i), standardDeviation(i));
273  return result;
274 }
275 
276 double GaussianSumUtilities1D::d1Pdf(const double& x) const { return d1Pdf(x, pdfComponents(x)); }
277 
278 double GaussianSumUtilities1D::d2Pdf(const double& x) const { return d2Pdf(x, pdfComponents(x)); }
279 
280 double GaussianSumUtilities1D::d3Pdf(const double& x) const { return d3Pdf(x, pdfComponents(x)); }
281 
282 double GaussianSumUtilities1D::lnPdf(const double& x) const { return lnPdf(x, pdfComponents(x)); }
283 
284 double GaussianSumUtilities1D::d1LnPdf(const double& x) const { return d1LnPdf(x, pdfComponents(x)); }
285 
286 double GaussianSumUtilities1D::d2LnPdf(const double& x) const { return d2LnPdf(x, pdfComponents(x)); }
287 
288 std::vector<double> GaussianSumUtilities1D::pdfComponents(const double& x) const {
289  std::vector<double> result;
290  result.reserve(size());
291  for (unsigned int i = 0; i < size(); i++)
292  result.push_back(weight(i) * gauss(x, mean(i), standardDeviation(i)));
293  return result;
294 }
295 
296 namespace {
297  struct PDF {
298  PDF(double ix) : x(ix) {}
299  double x;
300  double operator()(SingleGaussianState1D const& sg) const {
301  return sg.weight() * ROOT::Math::gaussian_pdf(x, sg.standardDeviation(), sg.mean());
302  }
303  };
304 } // namespace
305 void GaussianSumUtilities1D::pdfComponents(double x, std::vector<double>& result) const {
306  size_t s = size();
307  if (s != result.size())
308  result.resize(s);
309  std::transform(components().begin(), components().end(), result.begin(), PDF(x));
310 }
311 /*
312 void GaussianSumUtilities1D::pdfComponents (double x, std::vector<double> & result) const {
313  size_t s = size();
314  if (s!=result.size()) result.resize(s);
315  double* __restrict__ v = &result.front();
316  SingleGaussianState1D const * __restrict__ sgv = &components().front();
317  for ( unsigned int i=0; i<s; i++ )
318  v[i]= sgv[i].weight()*gauss(x,sgv[i].mean(),sgv[i].standardDeviation());
319 // result[i]=pdf(i,x);
320 }
321 */
322 
323 double GaussianSumUtilities1D::pdf(double, const std::vector<double>& pdfs) {
324  return std::accumulate(pdfs.begin(), pdfs.end(), 0.);
325 }
326 
327 double GaussianSumUtilities1D::d1Pdf(double x, const std::vector<double>& pdfs) const {
328  double result(0.);
329  size_t s = size();
330  for (unsigned int i = 0; i < s; i++) {
331  double dx = (x - mean(i)) / standardDeviation(i);
332  result += -pdfs[i] * dx / standardDeviation(i);
333  }
334  return result;
335 }
336 
337 double GaussianSumUtilities1D::d2Pdf(double x, const std::vector<double>& pdfs) const {
338  double result(0.);
339  size_t s = size();
340  for (unsigned int i = 0; i < s; i++) {
341  double dx = (x - mean(i)) / standardDeviation(i);
342  result += pdfs[i] / standardDeviation(i) / standardDeviation(i) * (dx * dx - 1);
343  }
344  return result;
345 }
346 
347 double GaussianSumUtilities1D::d3Pdf(double x, const std::vector<double>& pdfs) const {
348  double result(0.);
349  size_t s = size();
350  for (unsigned int i = 0; i < s; i++) {
351  double dx = (x - mean(i)) / standardDeviation(i);
352  result += pdfs[i] / standardDeviation(i) / standardDeviation(i) / standardDeviation(i) * (-dx * dx + 3) * dx;
353  }
354  return result;
355 }
356 
357 double GaussianSumUtilities1D::lnPdf(double x, const std::vector<double>& pdfs) {
358  double f(pdf(x, pdfs));
361  result = log(f);
362  return result;
363 }
364 
365 double GaussianSumUtilities1D::d1LnPdf(double x, const std::vector<double>& pdfs) const {
366  double f = pdf(x, pdfs);
367  double result(d1Pdf(x, pdfs));
369  result /= f;
370  else
371  result = 0.;
372  return result;
373 }
374 
375 double GaussianSumUtilities1D::d2LnPdf(double x, const std::vector<double>& pdfs) const {
376  double f = pdf(x, pdfs);
377  double df = d1LnPdf(x, pdfs);
378  double result(-df * df);
380  result += d2Pdf(x, pdfs) / f;
381  return result;
382 }
383 
384 double GaussianSumUtilities1D::gauss(double x, double mean, double sigma) {
385  // const double fNorm(1./sqrt(2*M_PI));
386  // double result(0.);
387 
388  // double d((x-mean)/sigma);
389  // if ( fabs(d)<20. ) result = exp(-d*d/2.);
390  // result *= fNorm/sigma;
391  // return result;
392  return ROOT::Math::gaussian_pdf(x, sigma, mean);
393 }
394 
395 double GaussianSumUtilities1D::gaussInt(double x, double mean, double sigma) {
396  return ROOT::Math::normal_cdf(x, sigma, mean);
397 }
398 
400  double s0(0.);
401  double s1(0.);
402  int s = size();
403  SingleGaussianState1D const* __restrict__ sgv = &components().front();
404  for (int i = 0; i < s; i++)
405  s0 += sgv[i].weight();
406  for (int i = 0; i < s; i++)
407  s1 += sgv[i].weight() * sgv[i].mean();
408  return s1 / s0;
409 }
410 
412  std::vector<double> pdfs;
413  pdfComponents(x, pdfs);
414  double result = -pdf(x, pdfs) / d2Pdf(x, pdfs);
415  // FIXME: wrong curvature seems to be non-existant but should add a proper recovery
416  if (result < 0.)
417  edm::LogWarning("GaussianSumUtilities") << "1D variance at mode < 0";
418  return result;
419 }
std::vector< double > pdfComponents(const double &) const
pdf components
static std::vector< std::string > checklist log
double weight() const
combined weight
const double w
Definition: UKUtility.cc:23
const MultiGaussianState1D & theState
double d2Pdf(const double &) const
second derivative of the p.d.f.
double d3Pdf(const double &) const
third derivative of the p.d.f.
double mean() const
combined mean
double weight() const
combined weight
static double gauss(double, double, double)
Value of gaussian distribution.
SingleGaussianState1D theMode
bool findMode(double &mode, double &pdfAtMode, const double &xStart, const double &scale) const
unsigned int size() const
number of components
double d1Pdf(const double &) const
first derivative of the p.d.f.
tuple result
Definition: mps_fire.py:311
double standardDeviation() const
standardDeviation
void computeMode() const
calculation of mode
U second(std::pair< T, U > const &p)
static double gaussInt(double, double, double)
Integrated value of gaussian distribution.
double mean() const
parameter vector
T sqrt(T t)
Definition: SSEVec.h:19
double variance() const
combined covariance
const SingleGaussianState1D & mode() const
uint16_t const *__restrict__ x
Definition: gpuClustering.h:39
double quantile(const double) const
Quantile (i.e. x for a given value of the c.d.f.)
double pdf(unsigned int i, double x) const
pdf of a single component at x
T min(T a, T b)
Definition: MathUtil.h:58
#define M_PI
double variance() const
combined variance
double mean() const
combined mean
double weight() const
weight
double combinedMean() const
Mean value of combined state.
double d2LnPdf(const double &) const
second derivative of ln(pdf)
string end
Definition: dataset.py:937
double localVariance(double x) const
double standardDeviation(unsigned int i) const
standard deviation of a component
Log< level::Warning, false > LogWarning
double lnPdf(const double &) const
ln(pdf)
void update(FinderState &state, double x) const
double cdf(const double &) const
value of the c.d.f.
double d1LnPdf(const double &) const
first derivative of ln(pdf)
const std::vector< SingleGaussianState1D > & components() const
components
bool modeIsValid() const
mode status
unsigned transform(const HcalDetId &id, unsigned transformCode)