npstat is hosted by Hepforge, IPPP Durham
NPStat  5.10.0
LOrPE1DVariableDegreeCVRunner.hh
Go to the documentation of this file.
1 #ifndef NPSTAT_LORPE1DVARIABLEDEGREECVRUNNER_HH_
2 #define NPSTAT_LORPE1DVARIABLEDEGREECVRUNNER_HH_
3 
4 /*!
5 // \file LOrPE1DVariableDegreeCVRunner.hh
6 //
7 // \brief Simultaneous optimization of LOrPE bandwidth and degree
8 // choice by cross-validation, assuming that the golden
9 // section search can succeed for both variables
10 //
11 // Author: I. Volobouev
12 //
13 // August 2022
14 */
15 
16 #include <cmath>
17 #include <climits>
18 
21 #include "npstat/nm/DualAxis.hh"
23 
24 #include "npstat/stat/LOrPE1DFixedDegreeCVRunner.hh"
25 
26 namespace npstat {
27  namespace Private {
28  template<class Lorpe>
29  class LOrPE1DVariableDegreeCVRunnerHelper : public Functor1<double,double>
30  {
31  public:
32  typedef LOrPE1DCVResult Status;
34 
36  Lorpe& lorpe, const LinInterpolatedTable1D& relativeBandwidths,
37  const double referenceDegree, const double referenceBandwidth,
38  const double tol)
39  : lorpe_(lorpe),
40  relativeBandwidths_(relativeBandwidths),
41  referenceDegree_(referenceDegree),
42  referenceBandwidth_(referenceBandwidth),
43  tol_(tol)
44  {
45  assert(referenceDegree_ >= 0.0);
46  assert(referenceBandwidth_ > 0.0);
47  assert(tol_ > 0.0);
48 
49  referenceBwFactor_ = relativeBandwidths_(referenceDegree_);
50  assert(referenceBwFactor_ > 0.0);
51  }
52 
53  inline virtual ~LOrPE1DVariableDegreeCVRunnerHelper() {}
54 
55  inline virtual double operator()(const double& degree) const
56  {
57  // Try to guess a good bandwidth value for this degree
58  const double bw1 = relativeBandwidths_(degree);
59  const double fr = bw1/referenceBwFactor_;
60  double bwGuess = referenceBandwidth_*fr;
61  assert(bwGuess > 0.0);
62 
63  if (!statusMap_.empty())
64  {
65  StatusMap::const_iterator closest = statusMap_.upper_bound(degree);
66  if (closest != statusMap_.begin())
67  --closest;
68  const double bw0 = relativeBandwidths_(closest->first);
69  const double f0 = bw1/bw0;
70  if (std::abs(std::log(f0)) < std::abs(std::log(fr)))
71  {
72  bwGuess = closest->second.bwFactor()*f0;
73  assert(bwGuess > 0.0);
74  }
75  }
76 
77  const LOrPE1DFixedDegreeCVRunner r(degree, bwGuess, tol_);
78  const Status& status = r.crossValidate(lorpe_);
79  const auto insertResult = statusMap_.insert(std::make_pair(degree,status));
80  assert(insertResult.second);
81  return -status.cvFunction();
82  }
83 
84  inline const StatusMap& getStatusMap() const {return statusMap_;}
85 
86  private:
87  Lorpe& lorpe_;
88  const LinInterpolatedTable1D& relativeBandwidths_;
89  double referenceDegree_;
90  double referenceBandwidth_;
91  double referenceBwFactor_;
92  double tol_;
93  mutable StatusMap statusMap_;
94  };
95  }
96 
98  {
99  public:
100  inline LOrPE1DVariableDegreeCVRunner(const LinInterpolatedTable1D& i_relativeBandwidths,
101  const double i_maxDeg,
102  const unsigned i_nDegsInTheGrid,
103  const double i_initialDeg,
104  const double i_initialBwFactorGuess,
105  const double i_initialDegStep,
106  const double i_bwTol)
107  : relativeBandwidths_(i_relativeBandwidths),
108  degAxis_(UniformAxis(i_nDegsInTheGrid, 0.0, i_maxDeg)),
109  initialDeg_(i_initialDeg),
110  initialBwFactorGuess_(i_initialBwFactorGuess),
111  initialDegStep_(i_initialDegStep),
112  bwTol_(i_bwTol)
113  {
114  assert(i_maxDeg > 0.0);
115  assert(initialDeg_ >= 0.0);
116  assert(initialDeg_ <= i_maxDeg);
117  assert(initialBwFactorGuess_ > 0.0);
118  assert(initialDegStep_ > 0.0);
119  assert(bwTol_ > 0.0);
120  }
121 
122  template<class Lorpe>
123  inline LOrPE1DCVResult crossValidate(Lorpe& lorpe) const
124  {
126  typedef LOrPE1DCVResult Result;
127 
129  initialDeg_, initialBwFactorGuess_, bwTol_);
130  const double referenceBandwidth = r.crossValidate(lorpe).bwFactor();
131  const Helper helper(lorpe, relativeBandwidths_, initialDeg_,
132  referenceBandwidth, bwTol_);
133  const double gridStep = degAxis_.intervalWidth();
134  const unsigned cellStep = std::round(initialDegStep_/gridStep);
135  const std::pair<unsigned,double>& where = degAxis_.getInterval(initialDeg_);
136  unsigned deg0 = where.first;
137  if (where.second < 0.5)
138  ++deg0;
139 
140  unsigned imin = UINT_MAX;
141  double fMinusOne, fmin, fPlusOne;
142 
143  const MinSearchStatus1D status = goldenSectionSearchOnAGrid(
144  helper, degAxis_, deg0, cellStep,
145  &imin, &fMinusOne, &fmin, &fPlusOne);
146  assert(status != MIN_SEARCH_FAILED);
147  assert(imin < degAxis_.nCoords());
148  const double degGuess = degAxis_.coordinate(imin);
149  Result resGuess = helper.getStatusMap()[degGuess];
150 
151  if (status == MIN_SEARCH_OK)
152  {
153  assert(imin);
154  assert(imin + 1U < degAxis_.nCoords());
155 
156  // Parabolic approximation in the degree variable
157  double bestDegree, extremumValue;
158  const bool isMinimum = parabolicExtremum(
159  degAxis_.coordinate(imin - 1U), fMinusOne,
160  degGuess, fmin,
161  degAxis_.coordinate(imin + 1U), fPlusOne,
162  &bestDegree, &extremumValue);
163  assert(isMinimum);
164 
165  const double bw0 = relativeBandwidths_(degGuess);
166  const double bw1 = relativeBandwidths_(bestDegree);
167  const double bwtry = resGuess.bwFactor()*bw1/bw0;
168  const LOrPE1DFixedDegreeCVRunner r2(bestDegree, bwtry, bwTol_);
169  Result bestGuess = r2.crossValidate(lorpe);
170  Result* bestResult = bestGuess.cvFunction() > resGuess.cvFunction() ?
171  &bestGuess : &resGuess;
172  bestResult->setDegreeBoundaryFlag(false);
173  return *bestResult;
174  }
175  else
176  // Optimum is on the boundary of the degree grid
177  return resGuess;
178  }
179 
180  private:
181  LinInterpolatedTable1D relativeBandwidths_;
182  DualAxis degAxis_;
183  double initialDeg_;
184  double initialBwFactorGuess_;
185  double initialDegStep_;
186  double bwTol_;
187  };
188 }
189 
190 #endif // NPSTAT_LORPE1DVARIABLEDEGREECVRUNNER_HH_
A variation of std::map with const subscripting operator.
Represent both equidistant and non-uniform coordinate sets for rectangular grids.
One-dimensional linear interpolation/extrapolation table.
Interface definitions and concrete simple functors for a variety of functor-based calculations.
Definition: DualAxis.hh:25
Definition: LOrPE1DCVResult.hh:19
Definition: LOrPE1DFixedDegreeCVRunner.hh:25
Definition: LOrPE1DVariableDegreeCVRunner.hh:98
Definition: LinInterpolatedTable1D.hh:39
Definition: LOrPE1DVariableDegreeCVRunner.hh:30
Definition: UniformAxis.hh:28
Definition: AbsArrayProjector.hh:14
MinSearchStatus1D goldenSectionSearchOnAGrid(const Functor1< double, double > &f, const DualAxis &axis, unsigned i0, unsigned initialStep, unsigned *imin, double *fMinusOne, double *fmin, double *fPlusOne)
bool parabolicExtremum(double x0, double y0, double x1, double y1, double x2, double y2, double *extremumCoordinate, double *extremumValue)
Definition: SimpleFunctors.hh:58