npstat is hosted by Hepforge, IPPP Durham
NPStat  5.10.0
solveForLOrPEWeights.hh
Go to the documentation of this file.
1 #ifndef NPSTAT_SOLVEFORLORPEWEIGHTS_HH_
2 #define NPSTAT_SOLVEFORLORPEWEIGHTS_HH_
3 
4 /*!
5 // \file solveForLOrPEWeights.hh
6 //
7 // \brief Solver for the non-linear Fredholm equation in the semiparametric
8 // mixture model with unbinned LOrPE
9 //
10 // Author: I. Volobouev
11 //
12 // July 2022
13 */
14 
15 #include <iosfwd>
16 #include <vector>
17 #include <cassert>
18 #include <utility>
19 #include <algorithm>
20 
23 
24 namespace npstat {
26  {
27  public:
28  inline LOrPEWeightsResult(const double i_alpha,
29  const bool i_converged,
30  const unsigned i_nIterations,
31  const LOrPE1DCVResult& cvResult)
32  : cvResult_(cvResult),
33  alpha_(i_alpha),
34  nIterations_(i_nIterations),
35  converged_(i_converged)
36  {
37  if (converged_)
38  assert(cvResult_.isValid());
39  }
40 
41  inline double filterDegree() const {return cvResult_.filterDegree();}
42  inline double bwFactor() const {return cvResult_.bwFactor();}
43  inline double cvFunction() const {return cvResult_.cvFunction();}
44  inline bool isOnDegreeBoundary() const {return cvResult_.isOnDegreeBoundary();}
45  inline bool isOnBandwidthBoundary() const {return cvResult_.isOnBandwidthBoundary();}
46 
47  inline double alpha() const {return alpha_;}
48  inline unsigned nIterations() const {return nIterations_;}
49  inline bool converged() const {return converged_;}
50 
51  void print(std::ostream& os) const;
52 
53  private:
54  LOrPE1DCVResult cvResult_;
55  double alpha_;
56  unsigned nIterations_;
57  bool converged_;
58  };
59 
60 
61  template<class Lorpe, class CvRunner, class ConvergenceCalculator>
62  inline LOrPEWeightsResult solveForLOrPEWeights(
63  Lorpe& lorpe, const CvRunner& cvRunner,
64  const AbsDistribution1D& signal, const double alpha,
65  const ConvergenceCalculator& conv, const unsigned maxIterations)
66  {
67  const auto& sample = lorpe.coords();
68  const unsigned long sampleSize = sample.size();
69 
70  std::vector<double> signalDensity(sampleSize);
71  for (unsigned long i=0; i<sampleSize; ++i)
72  signalDensity[i] = signal.density(sample[i].first);
73 
74  std::vector<double> weightBuffer(sampleSize*2);
75  double* previousWeights = &weightBuffer[0];
76  double* currentWeights = previousWeights + sampleSize;
77  for (unsigned long i=0; i<sampleSize; ++i)
78  previousWeights[i] = sample[i].second;
79 
80  std::vector<double> bgDensityBuffer(sampleSize*2);
81  double* previousBg = &bgDensityBuffer[0];
82  double* currentBg = previousBg + sampleSize;
83 
84  // Run the initial cross-validation
85  LOrPE1DCVResult cvResult = cvRunner.crossValidate(lorpe);
86 
87  {
88  // Create the initial background estimate
89  // at the sample points
90  const double filterDegree = cvResult.filterDegree();
91  const double bwFactor = cvResult.bwFactor();
92 
93  for (unsigned long i=0; i<sampleSize; ++i)
94  {
95  previousBg[i] = lorpe.density(
96  sample[i].first, filterDegree, bwFactor);
97  assert(previousBg[i] >= 0.0);
98  }
99  }
100 
101  bool converged = false;
102  unsigned iter = 0;
103  for (; iter<maxIterations && !converged; ++iter)
104  {
105  // Update the weights
106  for (unsigned long i=0; i<sampleSize; ++i)
107  {
108  if (previousBg[i] > 0.0)
109  {
110  const double d = alpha*signalDensity[i] +
111  (1.0 - alpha)*previousBg[i];
112  assert(d > 0.0);
113  currentWeights[i] = previousBg[i]/d;
114  }
115  else
116  currentWeights[i] = 0.0;
117  }
118  lorpe.setWeights(currentWeights, sampleSize);
119 
120  // Run cross-validation with the new weights
121  cvResult = cvRunner.crossValidate(lorpe);
122  const double filterDegree = cvResult.filterDegree();
123  const double bwFactor = cvResult.bwFactor();
124 
125  // Calculate background density
126  for (unsigned long i=0; i<sampleSize; ++i)
127  {
128  currentBg[i] = lorpe.density(
129  sample[i].first, filterDegree, bwFactor);
130  assert(currentBg[i] >= 0.0);
131  }
132 
133  // Check for convergence
134  converged = conv.converged(lorpe,
135  previousWeights, currentWeights,
136  previousBg, currentBg);
137 
138  // Rotate buffers
139  std::swap(previousWeights, currentWeights);
140  std::swap(previousBg, currentBg);
141  }
142 
143  return LOrPEWeightsResult(alpha, converged, iter, cvResult);
144  }
145 }
146 
147 std::ostream& operator<<(std::ostream& os, const npstat::LOrPEWeightsResult& res);
148 
149 #endif // NPSTAT_SOLVEFORLORPEWEIGHTS_HH_
Interface definition for 1-d continuous statistical distributions.
An object representing the result of the 1-d LOrPE cross-validation procedure.
Definition: LOrPE1DCVResult.hh:19
Definition: solveForLOrPEWeights.hh:26
Definition: AbsArrayProjector.hh:14
Definition: AbsDistribution1D.hh:31
virtual double density(double x) const =0