npstat is hosted by Hepforge, IPPP Durham
NPStat  5.10.0
LOrPE1DCV.hh
Go to the documentation of this file.
1 #ifndef NPSTAT_LORPE1DCV_HH_
2 #define NPSTAT_LORPE1DCV_HH_
3 
4 /*!
5 // \file LOrPE1DCV.hh
6 //
7 // \brief Unbinned density estimation by LOrPE with cross-validation
8 //
9 // Author: I. Volobouev
10 //
11 // June 2022
12 */
13 
14 #include <map>
15 #include <cmath>
16 #include <vector>
17 #include <climits>
18 #include <cassert>
19 #include <memory>
20 #include <utility>
21 #include <stdexcept>
22 #include <algorithm>
23 #include <sstream>
24 
25 #include "npstat/stat/LOrPE1D.hh"
26 
27 namespace npstat {
28  template <class Helper>
29  class LOrPE1DCVDensityFunctor : public Functor1<double, double>
30  {
31  public:
32  inline LOrPE1DCVDensityFunctor(const Helper& helper,
33  const double filterDegree,
34  const double bwFactor)
35  : helper_(helper),
36  filterDegree_(filterDegree),
37  bwFactor_(bwFactor)
38  {
39  if (filterDegree < 0.0) throw std::invalid_argument(
40  "In npstat::LOrPE1DCVDensityFunctor constructor: "
41  "filter degree can not be negative");
42  if (bwFactor <= 0.0) throw std::invalid_argument(
43  "In npstat::LOrPE1DCVDensityFunctor constructor: "
44  "bandwidth factor must be positive");
45  }
46 
47  inline virtual ~LOrPE1DCVDensityFunctor() {}
48 
49  inline double operator()(const double& x) const
50  {return helper_.density(x, filterDegree_, bwFactor_);}
51 
52  private:
53  const Helper& helper_;
54  double filterDegree_;
55  double bwFactor_;
56  };
57 
58  template <class Helper>
59  class LOrPE1DCVLocalizingWeightFunctor : public Functor1<double, double>
60  {
61  public:
62  inline LOrPE1DCVLocalizingWeightFunctor(const Helper& helper)
63  : helper_(helper) {}
64 
65  inline virtual ~LOrPE1DCVLocalizingWeightFunctor() {}
66 
67  inline double operator()(const double& x) const
68  {return helper_.cvLocalizingWeight(x);}
69 
70  private:
71  const Helper& helper_;
72  };
73 
74 
75  template <typename Numeric, class BwFcn, class WFcn>
76  class LOrPE1DCVFunctorHelper : public Functor1<double, double>,
77  public Functor2<double, double, double>
78  {
79  public:
80  typedef Numeric point_type;
81 
83  const int i_symbetaPower,
84  const double i_leftBoundary,
85  const double i_rightBoundary,
86  const BoundaryHandling& i_bh,
87  const BwFcn& i_bandwidthFunctor,
88  const WFcn& i_localizingWeight,
89  const double i_localizingWeightXmin,
90  const double i_localizingWeightXmax,
91  const unsigned i_nIntegIntervals,
92  const unsigned i_nIntegPoints,
93  const bool i_normalizeLOrPEEstimate,
94  const std::vector<Numeric>& i_coords)
95  : coords_(i_coords),
96  kernel_(0),
97  lastBwFactor_(-1.0),
98  lastNorm_(-1.0),
99  boundFilterDegree_(-1.0),
100  symbetaPower_(i_symbetaPower),
101  leftBoundary_(i_leftBoundary),
102  rightBoundary_(i_rightBoundary),
103  bh_(i_bh),
104  bandwidthFunctor_(i_bandwidthFunctor),
105  localizingWeight_(i_localizingWeight),
106  xminForWeight_(i_localizingWeightXmin),
107  xmaxForWeight_(i_localizingWeightXmax),
108  nIntegIntervals_(i_nIntegIntervals),
109  nIntegPoints_(i_nIntegPoints),
110  normalize_(i_normalizeLOrPEEstimate),
111  memoizeKernels_(false),
112  memoizeNorms_(false),
113  useMemoisingKernels_(false)
114  {
115  if (coords_.empty()) throw std::invalid_argument(
116  "In npstat::LOrPE1DCVFunctorHelper constructor: empty point sample");
117  if (leftBoundary_ >= rightBoundary_) throw std::invalid_argument(
118  "In npstat::LOrPE1DCVFunctorHelper constructor: invalid interval boundaries");
119  if (xminForWeight_ >= xmaxForWeight_) throw std::invalid_argument(
120  "In npstat::LOrPE1DCVFunctorHelper constructor: invalid weight boundaries");
121  if (!nIntegIntervals_) throw std::invalid_argument(
122  "In npstat::LOrPE1DCVFunctorHelper constructor: "
123  "number of integration intervals must be positive");
124  if (!GaussLegendreQuadrature::isAllowed(nIntegPoints_)) throw std::invalid_argument(
125  "In npstat::LOrPE1DCVFunctorHelper constructor: "
126  "unsupported number of integration points");
127  std::sort(coords_.begin(), coords_.end());
128  calculateEffectiveSampleSize();
129  }
130 
131  inline virtual ~LOrPE1DCVFunctorHelper() {}
132 
133  inline void bindFilterDegree(const double deg)
134  {
135  if (deg < 0.0) throw std::invalid_argument(
136  "In npstat::LOrPE1DCVFunctorHelper::bindFilterDegree: "
137  "filter degree can not be negative");
138  boundFilterDegree_ = deg;
139  }
140  inline void unbindFilterDegree()
141  {boundFilterDegree_ = -1.0;}
142  inline double boundFilterDegree() const
143  {return boundFilterDegree_;}
144 
145  /**
146  // This method with throw std::runtime_error if Numeric
147  // is not an std::pair
148  */
149  inline virtual void setWeights(const double* weights, unsigned long nWeights)
150  {
151  if (nWeights != coords_.size()) throw std::invalid_argument(
152  "In npstat::LOrPE1DCVFunctorHelper::setWeights: "
153  "incompatible length of the weight array");
154  Private::SetPairSeconds<Numeric>::set(&coords_[0], weights, nWeights);
155  calculateEffectiveSampleSize();
156  mapOfNorms_.clear();
157  lastBwFactor_ = -1.0;
158  }
159 
160  inline int symbetaPower() const {return symbetaPower_;}
161  inline double leftBoundary() const {return leftBoundary_;}
162  inline double rightBoundary() const {return rightBoundary_;}
163  inline BoundaryHandling bh() const {return bh_;}
164  inline double localizingWeightXmin() const {return xminForWeight_;}
165  inline double localizingWeighXmax() const {return xmaxForWeight_;}
166  inline unsigned nIntegIntervals() const {return nIntegIntervals_;}
167  inline unsigned nIntegPoints() const {return nIntegPoints_;}
168 
169  /** Is the density estimate auto-normalizing? */
170  inline bool normalizingLOrPEEstimate() const {return normalize_;}
171 
172  inline const std::vector<Numeric>& coords() const {return coords_;}
173  inline unsigned long nCoords() const {return coords_.size();}
174  inline Numeric minCoordinate() const {return coords_[0];}
175  inline Numeric maxCoordinate() const {return coords_.back();}
176  inline double totalSampleWeight() const {return sampleWeight_;}
177  inline double effectiveSampleSize() const {return effSampleSize_;}
178 
179  inline bool isMemoizingKernels() const {return memoizeKernels_;}
180  inline bool isMemoizingNorms() const {return memoizeNorms_;}
181  inline bool isUsingMemoisingKernels() const {return useMemoisingKernels_;}
182 
183  // The following modifiers should be called immediately
184  // after object creation
185  inline void memoizeKernels(const bool b) {memoizeKernels_ = b;}
186  inline void memoizeNorms(const bool b) {memoizeNorms_ = b;}
187  inline void useMemoisingKernels(const bool b)
188  {
189  assert(!kernel_);
190  useMemoisingKernels_ = b;
191  }
192 
193  // Clear some of the memoized information. Note that
194  // this will not clear the info memoized by the current
195  // kernel. Call "clearKernel" function after this one
196  // if you must clear everything.
197  inline void clearMemoizedInfo()
198  {
199  mapOfNorms_.clear();
200  mapOfKernels_.clear();
201  }
202 
203  inline void clearKernel()
204  {
205  kernel_ = std::shared_ptr<LOrPE1DSymbetaKernel>(0);
206  lastBwFactor_ = -1.0;
207  }
208 
209  inline double pointCoordinate(const unsigned long i) const
210  {
211  double x, w;
212  Private::coordAndWeight(coords_[i], &x, &w);
213  return x;
214  }
215 
216  inline double pointWeight(const unsigned long i) const
217  {
218  double x, w;
219  Private::coordAndWeight(coords_[i], &x, &w);
220  return w;
221  }
222 
223  inline double bandwidthCurve(const double x) const
224  {return fcnOrConst(bandwidthFunctor_, x);}
225 
226  inline double cvLocalizingWeight(const double x) const
227  {
228  const double xlolim = std::max(leftBoundary_, xminForWeight_);
229  const double xuplim = std::min(rightBoundary_, xmaxForWeight_);
230  if (x >= xlolim && x <= xuplim)
231  return fcnOrConst(localizingWeight_, x);
232  else
233  return 0.0;
234  }
235 
236  inline LOrPE1DCVLocalizingWeightFunctor<LOrPE1DCVFunctorHelper<Numeric, BwFcn, WFcn> >
237  cvLocalizingWeightFunctor() const
238  {
239  return LOrPE1DCVLocalizingWeightFunctor<LOrPE1DCVFunctorHelper<Numeric, BwFcn, WFcn> >(*this);
240  }
241 
242  inline double density(const double x, const double filterDegree,
243  const double bwFactor) const
244  {
245  setupKernel(filterDegree, bwFactor);
246  const double bw = bwFactor*fcnOrConst(bandwidthFunctor_, x);
247  return kernel_->lorpe(x, bw, &coords_[0], coords_.size(), true);
248  }
249 
250  inline double density(const double x, const double bwFactor) const
251  {
252  validateBoundDegree("density");
253  return density(x, boundFilterDegree_, bwFactor);
254  }
255 
256  inline LOrPE1DCVDensityFunctor<LOrPE1DCVFunctorHelper<Numeric, BwFcn, WFcn> >
257  densityFunctor(const double filterDegree, const double bwFactor) const
258  {
259  return LOrPE1DCVDensityFunctor<LOrPE1DCVFunctorHelper<Numeric, BwFcn, WFcn> >(
260  *this, filterDegree, bwFactor);
261  }
262 
263  inline LOrPE1DCVDensityFunctor<LOrPE1DCVFunctorHelper<Numeric, BwFcn, WFcn> >
264  densityFunctor(const double bwFactor) const
265  {
266  validateBoundDegree("densityFunctor");
267  return densityFunctor(boundFilterDegree_, bwFactor);
268  }
269 
270  inline LOrPE1D<Numeric> getLOrPE1D(
271  const double filterDegree, const double bwFactor) const
272  {
273  setupKernel(filterDegree, bwFactor);
274  LOrPE1D<Numeric> lorpe(*kernel_, coords_);
275  lorpe.setNormFactor(kernel_->normFactor());
276  return lorpe;
277  }
278 
279  inline LOrPE1D<Numeric> getLOrPE1D(const double bwFactor) const
280  {
281  validateBoundDegree("getLOrPE1D");
282  return getLOrPE1D(boundFilterDegree_, bwFactor);
283  }
284 
285  inline double operator()(
286  const double& filterDegree, const double& bwFactor) const
287  {
288  setupKernel(filterDegree, bwFactor);
289 
290  const unsigned long ncoords = coords_.size();
291  const Numeric* first = &coords_[0];
292  const Numeric* last = first + ncoords;
293  const double xlolim = std::max(leftBoundary_, xminForWeight_);
294  const double xuplim = std::min(rightBoundary_, xmaxForWeight_);
295  if (ncoords > 10UL)
296  {
297  const Numeric xlow = Private::WeightedCoord<Numeric>(xlolim, 0.0).value;
298  if (xlow > *first)
299  first = std::lower_bound(first, last, xlow);
300 
301  const Numeric xup = Private::WeightedCoord<Numeric>(xuplim, DBL_MAX).value;
302  if (xup < *(last - 1))
303  last = std::upper_bound(first, last, xup);
304  }
305 
306  long double msum = 0.0L;
307  double xi, w;
308  for (const Numeric* ptr = first; ptr != last; ++ptr)
309  {
310  Private::coordAndWeight(*ptr, &xi, &w);
311  assert(xi >= leftBoundary_ && xi <= rightBoundary_);
312  assert(w >= 0.0);
313  if (w > 0.0 && xi >= xlolim && xi <= xuplim)
314  {
315  const double localWeight = fcnOrConst(localizingWeight_, xi);
316  assert(localWeight >= 0.0);
317  if (localWeight > 0.0)
318  {
319  const double bw = bwFactor*fcnOrConst(bandwidthFunctor_, xi);
320  const double estimate = kernel_->lorpe(
321  xi, bw, &coords_[0], ncoords, true);
322  const double selfC = kernel_->getLastKernelAt0();
323  const double loo = (estimate - w*selfC)*sampleWeight_/(sampleWeight_ - w);
324  msum += pointContribution(selfC, loo, w, localWeight);
325  }
326  }
327  }
328  return valueToMaximize(msum);
329  }
330 
331  inline double operator()(const double& bwFactor) const
332  {
333  validateBoundDegree("operator()");
334  return operator()(boundFilterDegree_, bwFactor);
335  }
336 
337  /**
338  // This method will return meaningful results only
339  // if the automatic normalization is not turned on
340  */
341  inline double densityIntegral(
342  const double filterDegree, const double bwFactor) const
343  {
344  setupKernel(filterDegree, bwFactor);
345  GaussLegendreQuadrature glq(nIntegPoints_);
346  return glq.integrate(this->bwDensityFunctor(bwFactor),
347  leftBoundary_, rightBoundary_, nIntegIntervals_);
348  }
349 
350  inline double densityIntegral(const double bwFactor) const
351  {
352  validateBoundDegree("densityIntegral");
353  return densityIntegral(boundFilterDegree_, bwFactor);
354  }
355 
356  inline double integratedSquaredError(
357  const AbsDistribution1D& distro,
358  const double filterDegree, const double bwFactor) const
359  {
360  setupKernel(filterDegree, bwFactor);
361  LOrPE1DKernelISEFunctor<Numeric,BwFunctor> iseFcn(
362  distro, this->bwDensityFunctor(bwFactor));
363  GaussLegendreQuadrature glq(nIntegPoints_);
364  return glq.integrate(iseFcn, leftBoundary_,
365  rightBoundary_, nIntegIntervals_);
366  }
367 
368  inline double integratedSquaredError(
369  const AbsDistribution1D& distro, const double bwFactor) const
370  {
371  validateBoundDegree("integratedSquaredError");
372  return integratedSquaredError(distro, boundFilterDegree_, bwFactor);
373  }
374 
375  /** Is this class capable of cross-validation? */
376  inline static bool cvCapable() {return true;}
377 
378  protected:
379  typedef MultFunctor<BwFcn> BwFunctor;
380  typedef std::map<std::pair<double,double>,double> MapOfNorms;
381  typedef std::map<double,std::shared_ptr<LOrPE1DSymbetaKernel> > MapOfKernels;
382 
383  virtual double pointContribution(
384  double selfC, double leaveOneOutEstimate,
385  double pointWeight, double localWeight) const = 0;
386  virtual double valueToMaximize(double sum) const = 0;
387 
388  std::vector<Numeric> coords_;
389  double sampleWeight_;
390  double effSampleSize_;
391 
392  mutable std::shared_ptr<LOrPE1DSymbetaKernel> kernel_;
393  mutable double lastBwFactor_;
394  mutable double lastNorm_;
395 
396  double boundFilterDegree_;
397 
398  int symbetaPower_;
399  double leftBoundary_;
400  double rightBoundary_;
401  BoundaryHandling bh_;
402 
403  BwFcn bandwidthFunctor_;
404  WFcn localizingWeight_;
405  double xminForWeight_;
406  double xmaxForWeight_;
407  unsigned nIntegIntervals_;
408  unsigned nIntegPoints_;
409  bool normalize_;
410 
411  bool memoizeKernels_;
412  bool memoizeNorms_;
413  bool useMemoisingKernels_;
414 
415  mutable MapOfNorms mapOfNorms_;
416  mutable MapOfKernels mapOfKernels_;
417 
418  inline LOrPE1DFunctorHelper<Numeric,BwFunctor> bwDensityFunctor(
419  const double bwFactor) const
420  {
422  *kernel_, BwFunctor(bandwidthFunctor_, bwFactor),
423  &coords_[0], coords_.size(), true);
424  }
425 
426  private:
427  inline void validateBoundDegree(const char* where) const
428  {
429  if (boundFilterDegree_ < 0.0)
430  {
431  std::ostringstream os;
432  os << "In npstat::LOrPE1DCVFunctorHelper::" << where
433  << ": can't use the bandwidth factor alone, "
434  << "please bind the filter degree first";
435  throw std::runtime_error(os.str());
436  }
437  }
438 
439  inline void setupKernel(const double filterDegree,
440  const double bwFactor) const
441  {
442  if (filterDegree < 0.0) throw std::invalid_argument(
443  "In npstat::LOrPE1DCVFunctorHelper::setupKernel: "
444  "filter degree can not be negative");
445  if (bwFactor <= 0.0) throw std::invalid_argument(
446  "In npstat::LOrPE1DCVFunctorHelper::setupKernel: "
447  "bandwidth factor must be positive");
448 
449  const bool needAnotherKernel =
450  !(kernel_ && kernel_->filterDegree() == filterDegree);
451  if (needAnotherKernel)
452  makeKernel(filterDegree);
453 
454  // Check if precise auto normalization is requested
455  if (normalize_)
456  {
457  if (bwFactor == lastBwFactor_ && !needAnotherKernel)
458  {
459  assert(lastNorm_ > 0.0);
460  kernel_->setNormFactor(lastNorm_);
461  }
462  else
463  {
464  normalizeEstimate(bwFactor);
465  lastBwFactor_ = bwFactor;
466  lastNorm_ = kernel_->normFactor();
467  }
468  }
469  else
470  {
471  // Set up reasonable default normalization
472  kernel_->setNormFactor(1.0/sampleWeight_);
473  lastBwFactor_ = bwFactor;
474  lastNorm_ = kernel_->normFactor();
475  }
476  }
477 
478  inline void makeKernel(const double filterDegree) const
479  {
480  bool reallyMakeNewKernel = true;
481  if (memoizeKernels_)
482  {
483  kernel_ = mapOfKernels_[filterDegree];
484  reallyMakeNewKernel = !kernel_;
485  }
486  if (reallyMakeNewKernel)
487  {
488  LOrPE1DSymbetaKernel* k = new LOrPE1DSymbetaKernel(
489  symbetaPower_, filterDegree, leftBoundary_,
490  rightBoundary_, bh_, useMemoisingKernels_);
491  kernel_ = std::shared_ptr<LOrPE1DSymbetaKernel>(k);
492 
493  if (memoizeKernels_)
494  mapOfKernels_[filterDegree] = kernel_;
495  }
496  }
497 
498  inline void normalizeEstimate(const double bwFactor) const
499  {
500  assert(kernel_);
501 
502  bool reallyRecalculateNorm = true;
503  if (memoizeNorms_)
504  {
505  const double deg = kernel_->filterDegree();
506  MapOfNorms::iterator it = mapOfNorms_.find(std::make_pair(deg, bwFactor));
507  if (it != mapOfNorms_.end())
508  {
509  reallyRecalculateNorm = false;
510  kernel_->setNormFactor(it->second);
511  }
512  }
513 
514  if (reallyRecalculateNorm)
515  {
516  const double defaultNorm = 1.0/sampleWeight_;
517  kernel_->setNormFactor(defaultNorm);
518  GaussLegendreQuadrature glq(nIntegPoints_);
519  const double integ = glq.integrate(this->bwDensityFunctor(bwFactor),
520  leftBoundary_, rightBoundary_, nIntegIntervals_);
521  assert(integ > 0.0);
522  const double newNorm = defaultNorm/integ;
523  kernel_->setNormFactor(newNorm);
524 
525  if (memoizeNorms_)
526  {
527  const double deg = kernel_->filterDegree();
528  mapOfNorms_[std::make_pair(deg, bwFactor)] = newNorm;
529  }
530  }
531  }
532 
533  inline void calculateEffectiveSampleSize()
534  {
535  sampleWeight_ = Private::SampleWeight<Numeric>(coords_).value;
536  if (sampleWeight_ <= 0.0) throw std::invalid_argument(
537  "In npstat::LOrPE1DCV::calculateEffectiveSampleSize: "
538  "total sample weight must be positive");
539  const double sumWsq = Private::SampleSquaredWeight<Numeric>(coords_).value;
540  effSampleSize_ = sampleWeight_/sumWsq*sampleWeight_;
541  }
542 
543 #ifdef SWIG
544  public:
545  inline std::vector<double> sortedCoords() const
546  {
547  const unsigned long sz = coords_.size();
548  std::vector<double> out;
549  out.reserve(sz);
550  double x, w;
551  for (unsigned long i = 0; i < sz; ++i)
552  {
553  Private::coordAndWeight(coords_[i], &x, &w);
554  out.push_back(x);
555  }
556  return out;
557  }
558 
559  inline std::vector<double> sortedCoordWeights() const
560  {
561  const unsigned long sz = coords_.size();
562  std::vector<double> out;
563  out.reserve(sz);
564  double x, w;
565  for (unsigned long i = 0; i < sz; ++i)
566  {
567  Private::coordAndWeight(coords_[i], &x, &w);
568  out.push_back(w);
569  }
570  return out;
571  }
572 #endif
573  };
574 
575  template <typename Numeric, class BwFcn, class WFcn>
576  class LOrPE1DLSCVFunctorHelper : public LOrPE1DCVFunctorHelper<Numeric, BwFcn, WFcn>
577  {
578  public:
580 
581  using Base::LOrPE1DCVFunctorHelper;
582 
583  inline virtual ~LOrPE1DLSCVFunctorHelper() {}
584 
585  protected:
586  inline virtual double pointContribution(
587  const double /* selfC */, const double leaveOneOutEstimate,
588  const double pointWeight, const double localWeight) const
589  {
590  return pointWeight*localWeight*leaveOneOutEstimate;
591  }
592 
593  inline virtual double valueToMaximize(const double sum) const
594  {
595  const double xlolim = std::max(Base::leftBoundary_, Base::xminForWeight_);
596  const double xuplim = std::min(Base::rightBoundary_, Base::xmaxForWeight_);
597  GaussLegendreQuadrature glq(Base::nIntegPoints_);
598  const double integ = glq.integrate(
599  make_DensitySquaredTimesWeight(
600  this->bwDensityFunctor(Base::lastBwFactor_), Base::localizingWeight_),
601  xlolim, xuplim, Base::nIntegIntervals_);
602  return -(integ - sum*2.0/Base::sampleWeight_);
603  }
604  };
605 
606  template <typename Numeric, class BwFcn, class WFcn>
607  class LOrPE1DRLCVFunctorHelper : public LOrPE1DCVFunctorHelper<Numeric, BwFcn, WFcn>
608  {
609  public:
611 
613  const int i_symbetaPower,
614  const double i_leftBoundary,
615  const double i_rightBoundary,
616  const BoundaryHandling& i_bh,
617  const BwFcn& i_bandwidthFunctor,
618  const WFcn& i_localizingWeight,
619  const double i_localizingWeightXmin,
620  const double i_localizingWeightXmax,
621  const unsigned i_nIntegIntervals,
622  const unsigned i_nIntegPoints,
623  const bool i_normalizeLOrPEEstimate,
624  const std::vector<Numeric>& i_coords,
625  const double i_rlcvAlpha = 0.5)
626  : Base(
627  i_symbetaPower, i_leftBoundary, i_rightBoundary,
628  i_bh, i_bandwidthFunctor, i_localizingWeight,
629  i_localizingWeightXmin, i_localizingWeightXmax,
630  i_nIntegIntervals, i_nIntegPoints,
631  i_normalizeLOrPEEstimate, i_coords)
632  {
633  setRlcvAlpha(i_rlcvAlpha);
634  }
635 
636  inline virtual ~LOrPE1DRLCVFunctorHelper() {}
637 
638  inline void setRlcvAlpha(const double alpha)
639  {
640  rlcvAlpha_ = alpha;
641  minDensFactor_ = std::pow(Base::effSampleSize_, alpha);
642  }
643 
644  inline virtual void setWeights(const double* weights, unsigned long nWeights)
645  {
646  Base::setWeights(weights, nWeights);
647  minDensFactor_ = std::pow(Base::effSampleSize_, rlcvAlpha_);
648  }
649 
650  inline double rlcvAlpha() const {return rlcvAlpha_;}
651 
652  protected:
653  inline virtual double pointContribution(
654  const double selfC, const double leaveOneOutEstimate,
655  const double pointWeight, const double localWeight) const
656  {
657  const double minDens = selfC/minDensFactor_;
658  return pointWeight*localWeight*std::log(std::max(leaveOneOutEstimate, minDens));
659  }
660 
661  inline virtual double valueToMaximize(const double sum) const
662  {
663  return sum;
664  }
665 
666  private:
667  double rlcvAlpha_;
668  double minDensFactor_;
669  };
670 
671  /** A convenience function for creating LOrPE1DLSCVFunctorHelper objects */
672  template <typename Numeric, class BwFcn, class WFcn>
673  inline LOrPE1DLSCVFunctorHelper<Numeric, BwFcn, WFcn>
674  LOrPE1DLSCVFunctor(const int i_symbetaPower,
675  const double i_leftBoundary,
676  const double i_rightBoundary,
677  const BoundaryHandling& i_bh,
678  const BwFcn& i_bandwidthFunctor,
679  const WFcn& i_localizingWeight,
680  const double i_localizingWeightXmin,
681  const double i_localizingWeightXmax,
682  const unsigned i_nIntegIntervals,
683  const unsigned i_nIntegPoints,
684  const bool i_normalizeLOrPEEstimate,
685  const std::vector<Numeric>& i_coords)
686  {
688  i_symbetaPower, i_leftBoundary, i_rightBoundary,
689  i_bh, i_bandwidthFunctor, i_localizingWeight,
690  i_localizingWeightXmin, i_localizingWeightXmax,
691  i_nIntegIntervals, i_nIntegPoints,
692  i_normalizeLOrPEEstimate, i_coords);
693  }
694 
695  /**
696  // A convenience function for creating LOrPE1DLSCVFunctorHelper objects
697  // that perform global cross-validation (i.e., without CV localization
698  // function).
699  */
700  template <typename Numeric, class BwFcn>
701  inline LOrPE1DLSCVFunctorHelper<Numeric, BwFcn, double>
702  LOrPE1DGlobLSCVFunctor(const int i_symbetaPower,
703  const double i_leftBoundary,
704  const double i_rightBoundary,
705  const BoundaryHandling& i_bh,
706  const BwFcn& i_bandwidthFunctor,
707  const unsigned i_nIntegIntervals,
708  const unsigned i_nIntegPoints,
709  const bool i_normalizeLOrPEEstimate,
710  const std::vector<Numeric>& i_coords)
711  {
713  i_symbetaPower, i_leftBoundary, i_rightBoundary,
714  i_bh, i_bandwidthFunctor,
715  1.0, -DBL_MAX, DBL_MAX,
716  i_nIntegIntervals, i_nIntegPoints,
717  i_normalizeLOrPEEstimate, i_coords);
718  }
719 
720  /**
721  // A convenience function for creating LOrPE1DLSCVFunctorHelper objects
722  // that perform global cross-validation (i.e., without CV localization
723  // function) and use constant bandwidth.
724  */
725  template <typename Numeric>
726  inline LOrPE1DLSCVFunctorHelper<Numeric, double, double>
727  LOrPE1DSimpleLSCVFunctor(const int i_symbetaPower,
728  const double i_leftBoundary,
729  const double i_rightBoundary,
730  const BoundaryHandling& i_bh,
731  const unsigned i_nIntegIntervals,
732  const unsigned i_nIntegPoints,
733  const bool i_normalizeLOrPEEstimate,
734  const std::vector<Numeric>& i_coords)
735  {
737  i_symbetaPower, i_leftBoundary, i_rightBoundary,
738  i_bh, 1.0, 1.0, -DBL_MAX, DBL_MAX,
739  i_nIntegIntervals, i_nIntegPoints,
740  i_normalizeLOrPEEstimate, i_coords);
741  }
742 
743  /** A convenience function for creating LOrPE1DRLCVFunctorHelper objects */
744  template <typename Numeric, class BwFcn, class WFcn>
745  inline LOrPE1DRLCVFunctorHelper<Numeric, BwFcn, WFcn>
746  LOrPE1DRLCVFunctor(const int i_symbetaPower,
747  const double i_leftBoundary,
748  const double i_rightBoundary,
749  const BoundaryHandling& i_bh,
750  const BwFcn& i_bandwidthFunctor,
751  const WFcn& i_localizingWeight,
752  const double i_localizingWeightXmin,
753  const double i_localizingWeightXmax,
754  const unsigned i_nIntegIntervals,
755  const unsigned i_nIntegPoints,
756  const bool i_normalizeLOrPEEstimate,
757  const std::vector<Numeric>& i_coords,
758  const double i_rlcvAlpha = 0.5)
759  {
761  i_symbetaPower, i_leftBoundary, i_rightBoundary,
762  i_bh, i_bandwidthFunctor, i_localizingWeight,
763  i_localizingWeightXmin, i_localizingWeightXmax,
764  i_nIntegIntervals, i_nIntegPoints,
765  i_normalizeLOrPEEstimate, i_coords, i_rlcvAlpha);
766  }
767 
768  /**
769  // A convenience function for creating LOrPE1DRLCVFunctorHelper objects
770  // that perform global cross-validation (i.e., without CV localization
771  // function).
772  */
773  template <typename Numeric, class BwFcn>
774  inline LOrPE1DRLCVFunctorHelper<Numeric, BwFcn, double>
775  LOrPE1DGlobRLCVFunctor(const int i_symbetaPower,
776  const double i_leftBoundary,
777  const double i_rightBoundary,
778  const BoundaryHandling& i_bh,
779  const BwFcn& i_bandwidthFunctor,
780  const unsigned i_nIntegIntervals,
781  const unsigned i_nIntegPoints,
782  const bool i_normalizeLOrPEEstimate,
783  const std::vector<Numeric>& i_coords,
784  const double i_rlcvAlpha = 0.5)
785  {
787  i_symbetaPower, i_leftBoundary, i_rightBoundary,
788  i_bh, i_bandwidthFunctor,
789  1.0, -DBL_MAX, DBL_MAX,
790  i_nIntegIntervals, i_nIntegPoints,
791  i_normalizeLOrPEEstimate, i_coords, i_rlcvAlpha);
792  }
793 
794  /**
795  // A convenience function for creating LOrPE1DRLCVFunctorHelper objects
796  // that perform global cross-validation (i.e., without CV localization
797  // function) and use constant bandwidth.
798  */
799  template <typename Numeric>
800  inline LOrPE1DRLCVFunctorHelper<Numeric, double, double>
801  LOrPE1DSimpleRLCVFunctor(const int i_symbetaPower,
802  const double i_leftBoundary,
803  const double i_rightBoundary,
804  const BoundaryHandling& i_bh,
805  const unsigned i_nIntegIntervals,
806  const unsigned i_nIntegPoints,
807  const bool i_normalizeLOrPEEstimate,
808  const std::vector<Numeric>& i_coords,
809  const double i_rlcvAlpha = 0.5)
810  {
812  i_symbetaPower, i_leftBoundary, i_rightBoundary,
813  i_bh, 1.0, 1.0, -DBL_MAX, DBL_MAX,
814  i_nIntegIntervals, i_nIntegPoints,
815  i_normalizeLOrPEEstimate, i_coords, i_rlcvAlpha);
816  }
817 
818  // Convenience functions for creating either RLCV or LSCV
819  // functors. The convention is that LSCV will be used in case
820  // rlcvAlpha parameter is negative.
821  template <typename Numeric, class BwFcn, class WFcn>
822  inline std::unique_ptr<LOrPE1DCVFunctorHelper<Numeric, BwFcn, WFcn> >
823  LOrPE1DCVFunctor(const int i_symbetaPower,
824  const double i_leftBoundary,
825  const double i_rightBoundary,
826  const BoundaryHandling& i_bh,
827  const BwFcn& i_bandwidthFunctor,
828  const WFcn& i_localizingWeight,
829  const double i_localizingWeightXmin,
830  const double i_localizingWeightXmax,
831  const unsigned i_nIntegIntervals,
832  const unsigned i_nIntegPoints,
833  const bool i_normalizeLOrPEEstimate,
834  const std::vector<Numeric>& i_coords,
835  const double i_rlcvAlpha)
836  {
837  typedef LOrPE1DCVFunctorHelper<Numeric, BwFcn, WFcn> Base;
838  typedef LOrPE1DRLCVFunctorHelper<Numeric, BwFcn, WFcn> RLCV;
839  typedef LOrPE1DLSCVFunctorHelper<Numeric, BwFcn, WFcn> LSCV;
840 
841  Base* ptr = 0;
842  if (i_rlcvAlpha < 0.0)
843  ptr = new LSCV(
844  i_symbetaPower, i_leftBoundary, i_rightBoundary,
845  i_bh, i_bandwidthFunctor, i_localizingWeight,
846  i_localizingWeightXmin, i_localizingWeightXmax,
847  i_nIntegIntervals, i_nIntegPoints,
848  i_normalizeLOrPEEstimate, i_coords);
849  else
850  ptr = new RLCV(
851  i_symbetaPower, i_leftBoundary, i_rightBoundary,
852  i_bh, i_bandwidthFunctor, i_localizingWeight,
853  i_localizingWeightXmin, i_localizingWeightXmax,
854  i_nIntegIntervals, i_nIntegPoints,
855  i_normalizeLOrPEEstimate, i_coords, i_rlcvAlpha);
856  return std::unique_ptr<Base>(ptr);
857  }
858 
859  template <typename Numeric, class BwFcn>
860  inline std::unique_ptr<LOrPE1DCVFunctorHelper<Numeric, BwFcn, double> >
861  LOrPE1DGlobCVFunctor(const int i_symbetaPower,
862  const double i_leftBoundary,
863  const double i_rightBoundary,
864  const BoundaryHandling& i_bh,
865  const BwFcn& i_bandwidthFunctor,
866  const unsigned i_nIntegIntervals,
867  const unsigned i_nIntegPoints,
868  const bool i_normalizeLOrPEEstimate,
869  const std::vector<Numeric>& i_coords,
870  const double i_rlcvAlpha)
871  {
872  typedef LOrPE1DCVFunctorHelper<Numeric, BwFcn, double> Base;
873  typedef LOrPE1DRLCVFunctorHelper<Numeric, BwFcn, double> RLCV;
874  typedef LOrPE1DLSCVFunctorHelper<Numeric, BwFcn, double> LSCV;
875 
876  Base* ptr = 0;
877  if (i_rlcvAlpha < 0.0)
878  ptr = new LSCV(
879  i_symbetaPower, i_leftBoundary, i_rightBoundary,
880  i_bh, i_bandwidthFunctor,
881  1.0, -DBL_MAX, DBL_MAX,
882  i_nIntegIntervals, i_nIntegPoints,
883  i_normalizeLOrPEEstimate, i_coords);
884  else
885  ptr = new RLCV(
886  i_symbetaPower, i_leftBoundary, i_rightBoundary,
887  i_bh, i_bandwidthFunctor,
888  1.0, -DBL_MAX, DBL_MAX,
889  i_nIntegIntervals, i_nIntegPoints,
890  i_normalizeLOrPEEstimate, i_coords, i_rlcvAlpha);
891  return std::unique_ptr<Base>(ptr);
892  }
893 
894  template <typename Numeric>
895  inline std::unique_ptr<LOrPE1DCVFunctorHelper<Numeric, double, double> >
896  LOrPE1DSimpleCVFunctor(const int i_symbetaPower,
897  const double i_leftBoundary,
898  const double i_rightBoundary,
899  const BoundaryHandling& i_bh,
900  const unsigned i_nIntegIntervals,
901  const unsigned i_nIntegPoints,
902  const bool i_normalizeLOrPEEstimate,
903  const std::vector<Numeric>& i_coords,
904  const double i_rlcvAlpha)
905  {
906  typedef LOrPE1DCVFunctorHelper<Numeric, double, double> Base;
907  typedef LOrPE1DRLCVFunctorHelper<Numeric, double, double> RLCV;
908  typedef LOrPE1DLSCVFunctorHelper<Numeric, double, double> LSCV;
909 
910  Base* ptr = 0;
911  if (i_rlcvAlpha < 0.0)
912  ptr = new LSCV(
913  i_symbetaPower, i_leftBoundary, i_rightBoundary,
914  i_bh, 1.0, 1.0, -DBL_MAX, DBL_MAX,
915  i_nIntegIntervals, i_nIntegPoints,
916  i_normalizeLOrPEEstimate, i_coords);
917  else
918  ptr = new RLCV(
919  i_symbetaPower, i_leftBoundary, i_rightBoundary,
920  i_bh, 1.0, 1.0, -DBL_MAX, DBL_MAX,
921  i_nIntegIntervals, i_nIntegPoints,
922  i_normalizeLOrPEEstimate, i_coords, i_rlcvAlpha);
923  return std::unique_ptr<Base>(ptr);
924  }
925 }
926 
927 #endif // NPSTAT_LORPE1DCV_HH_
Convenience class which aggregates the kernel and the data for unbinned density estimation by LOrPE.
Definition: BoundaryHandling.hh:21
Definition: GaussLegendreQuadrature.hh:27
long double integrate(const Functor1< FcnResult, FcnArg > &fcn, long double a, long double b) const
static bool isAllowed(unsigned npoints)
Definition: LOrPE1DCV.hh:30
Definition: LOrPE1DCV.hh:78
bool normalizingLOrPEEstimate() const
Definition: LOrPE1DCV.hh:170
virtual void setWeights(const double *weights, unsigned long nWeights)
Definition: LOrPE1DCV.hh:149
static bool cvCapable()
Definition: LOrPE1DCV.hh:376
double densityIntegral(const double filterDegree, const double bwFactor) const
Definition: LOrPE1DCV.hh:341
Definition: LOrPE1DCV.hh:60
Definition: LOrPE1DSymbetaKernel.hh:173
Definition: LOrPE1DCV.hh:577
Definition: LOrPE1DCV.hh:608
virtual void setWeights(const double *weights, unsigned long nWeights)
Definition: LOrPE1DCV.hh:644
Definition: fcnOrConst.hh:42
Definition: AbsArrayProjector.hh:14
LOrPE1DLSCVFunctorHelper< Numeric, BwFcn, double > LOrPE1DGlobLSCVFunctor(const int i_symbetaPower, const double i_leftBoundary, const double i_rightBoundary, const BoundaryHandling &i_bh, const BwFcn &i_bandwidthFunctor, const unsigned i_nIntegIntervals, const unsigned i_nIntegPoints, const bool i_normalizeLOrPEEstimate, const std::vector< Numeric > &i_coords)
Definition: LOrPE1DCV.hh:702
LOrPE1DLSCVFunctorHelper< Numeric, double, double > LOrPE1DSimpleLSCVFunctor(const int i_symbetaPower, const double i_leftBoundary, const double i_rightBoundary, const BoundaryHandling &i_bh, const unsigned i_nIntegIntervals, const unsigned i_nIntegPoints, const bool i_normalizeLOrPEEstimate, const std::vector< Numeric > &i_coords)
Definition: LOrPE1DCV.hh:727
LOrPE1DRLCVFunctorHelper< Numeric, BwFcn, double > LOrPE1DGlobRLCVFunctor(const int i_symbetaPower, const double i_leftBoundary, const double i_rightBoundary, const BoundaryHandling &i_bh, const BwFcn &i_bandwidthFunctor, const unsigned i_nIntegIntervals, const unsigned i_nIntegPoints, const bool i_normalizeLOrPEEstimate, const std::vector< Numeric > &i_coords, const double i_rlcvAlpha=0.5)
Definition: LOrPE1DCV.hh:775
LOrPE1DLSCVFunctorHelper< Numeric, BwFcn, WFcn > LOrPE1DLSCVFunctor(const int i_symbetaPower, const double i_leftBoundary, const double i_rightBoundary, const BoundaryHandling &i_bh, const BwFcn &i_bandwidthFunctor, const WFcn &i_localizingWeight, const double i_localizingWeightXmin, const double i_localizingWeightXmax, const unsigned i_nIntegIntervals, const unsigned i_nIntegPoints, const bool i_normalizeLOrPEEstimate, const std::vector< Numeric > &i_coords)
Definition: LOrPE1DCV.hh:674
LOrPE1DRLCVFunctorHelper< Numeric, BwFcn, WFcn > LOrPE1DRLCVFunctor(const int i_symbetaPower, const double i_leftBoundary, const double i_rightBoundary, const BoundaryHandling &i_bh, const BwFcn &i_bandwidthFunctor, const WFcn &i_localizingWeight, const double i_localizingWeightXmin, const double i_localizingWeightXmax, const unsigned i_nIntegIntervals, const unsigned i_nIntegPoints, const bool i_normalizeLOrPEEstimate, const std::vector< Numeric > &i_coords, const double i_rlcvAlpha=0.5)
Definition: LOrPE1DCV.hh:746
LOrPE1DRLCVFunctorHelper< Numeric, double, double > LOrPE1DSimpleRLCVFunctor(const int i_symbetaPower, const double i_leftBoundary, const double i_rightBoundary, const BoundaryHandling &i_bh, const unsigned i_nIntegIntervals, const unsigned i_nIntegPoints, const bool i_normalizeLOrPEEstimate, const std::vector< Numeric > &i_coords, const double i_rlcvAlpha=0.5)
Definition: LOrPE1DCV.hh:801
Definition: SimpleFunctors.hh:58
Definition: SimpleFunctors.hh:89
Definition: coordAndWeight.hh:104