1 #ifndef NPSI_MINUITSEMIPARAMETRICFITFCN1D_HH_
2 #define NPSI_MINUITSEMIPARAMETRICFITFCN1D_HH_
21 #include "Minuit2/MnUserParameters.h"
22 #include "Minuit2/MnMinimize.h"
23 #include "Minuit2/FunctionMinimum.h"
48 template <
typename Numeric,
class DensityConstructor,
typename NumIn=
double>
210 const DensityConstructor& densityMaker,
213 const int symmetricBetaPower,
214 const double minimumBgFeatureSize,
215 const NumIn* initialApproximation = 0,
216 const unsigned lenApproximation = 0U,
217 const int polyDegreeLimit = -1,
218 const bool verbose =
true,
219 const unsigned cvmode =
220 npstat::CV_MODE_LINEARIZED,
221 const bool useLeastSquaresCV =
true,
222 const bool refitBandwidth =
true,
223 const bool refitPolyDegree =
true,
224 const double regularizationParameter = -1.0,
225 const unsigned nIntegrationPoints = 0U,
226 const double bandwidthUpperLimitFactor=5.0,
227 const unsigned pseudoFitCycles = 0U,
228 const double convergenceEpsilon = 0.0,
229 const double pseudoFitPrecision = 0.0,
230 const unsigned bandwidthScanPoints = 64U,
231 const double minlog = log(DBL_MIN),
232 const double up = 0.5,
233 const double upRefit = 0.05,
234 const unsigned maxIterations = 10000U)
235 : signalDensityBuffer_(histo.nBins(), 0.0),
236 bgDensityBuffer_(histo.nBins(), 0.0),
239 densityMaker_(densityMaker),
240 minimumBgFeatureSize_(minimumBgFeatureSize),
241 convergenceEpsilon_(convergenceEpsilon),
242 pseudoFitPrecision_(pseudoFitPrecision),
245 signalFraction_(0.0),
248 upNonparametric_(upRefit),
249 regularizationParameter_(regularizationParameter),
250 bandwidthLimitFactor_(bandwidthUpperLimitFactor),
251 maxBgEventsInWindow_(-1.0),
253 nIntegrationPoints_(nIntegrationPoints),
254 maxIterations_(maxIterations),
255 nFitCycles_(pseudoFitCycles),
256 polyDegreeLimit_(polyDegreeLimit),
258 bandwidthScanPoints_(bandwidthScanPoints),
259 m_(symmetricBetaPower),
262 refitBandwidth_(refitBandwidth),
263 refitPolyDegree_(refitPolyDegree),
265 useLeastSquaresCV_(useLeastSquaresCV)
267 if (histo_.dim() != 1U)
throw std::invalid_argument(
268 "In npsi::MinuitSemiparametricFitFcn1D constructor : "
269 "only 1-d histograms can be used with this class");
271 if (initialApproximation && lenApproximation)
273 initialApproximation_.reserve(lenApproximation);
274 for (
unsigned i=0; i<lenApproximation; ++i)
275 initialApproximation_.push_back(initialApproximation[i]);
278 if (convergenceEpsilon_ == 0.0)
279 convergenceEpsilon_ = 10.0*DBL_EPSILON*histo.
nBins();
280 if (pseudoFitPrecision_ == 0.0)
281 pseudoFitPrecision_ = 10.0*convergenceEpsilon_;
283 if (polyDegreeLimit >= 0)
284 if (
static_cast<unsigned>(polyDegreeLimit) >
286 throw std::invalid_argument(
287 "In npsi::MinuitSemiparametricFitFcn1D constructor: "
288 "polynomial degree limit outside of supported range");
290 if (minimumBgFeatureSize_ < 0.0)
291 throw std::invalid_argument(
292 "In npsi::MinuitSemiparametricFitFcn1D constructor: "
293 "minimum feature size can not be negative");
295 nEvents_ = histo_.binContents().template sum<long double>();
300 inline double Up()
const {
return up_;}
302 inline double lastBandwidthUsed()
const {
return bandwidth_;}
304 inline double lastPolyDegreeUsed()
const {
return maxDegree_;}
312 inline double lastSignalFractionUsed()
const {
return signalFraction_;}
314 inline const std::vector<double>& lastBackgroundFitted()
const
315 {
return bgDensityBuffer_;}
317 inline const std::vector<double>& lastSignalFitted()
const
318 {
return signalDensityBuffer_;}
320 inline unsigned long callCount()
const {
return callCount_;}
322 inline double crossValidationPrecision()
const
323 {
return pseudoFitPrecision_;}
325 inline int symbetaPower()
const {
return m_;}
327 inline double maxBgEventsInGaussWindow()
const
328 {
return maxBgEventsInWindow_;}
333 inline std::vector<double> lastDensityFitted()
const
335 const double bgfrac = 1.0 - signalFraction_;
336 const unsigned nbins = histo_.nBins();
337 std::vector<double> dvec(nbins);
338 for (
unsigned i=0; i<nbins; ++i)
339 dvec[i] = signalFraction_*signalDensityBuffer_[i] +
340 bgfrac*bgDensityBuffer_[i];
362 virtual double operator()(
const std::vector<double>& x)
const
364 const unsigned npara = x.size();
365 if (npara < 3U)
throw std::invalid_argument(
366 "In npsi::MinuitSemiparametricFitFcn1D::operator(): "
367 "insufficient number of parameters, need at least 3");
371 signalFraction_ = x[2];
373 if (!refitBandwidth_ && bandwidth_ <= 0.0)
374 throw std::invalid_argument(
375 "In npsi::MinuitSemiparametricFitFcn1D::operator(): "
376 "if not refitted, the bandwidth must be positive");
378 if (!refitPolyDegree_ && maxDegree_ < 0.0)
379 throw std::invalid_argument(
380 "In npsi::MinuitSemiparametricFitFcn1D::operator(): "
381 "if not refitted, polynomial degree can not be negative");
383 if (signalParameters_.size() != npara - 3U)
384 signalParameters_.resize(npara - 3U);
385 for (
unsigned i=3U; i<npara; ++i)
386 signalParameters_[i - 3U] = x[i];
388 densityMaker_(signalParameters_);
390 const unsigned lenApprox = initialApproximation_.size();
391 const NumIn* initApprox = 0;
393 initApprox = &initialApproximation_[0];
405 double winBgEvents = 1.0;
408 if (maxBgEventsInWindow_ <= 0.0)
410 maxBgEventsInWindow_ = 1.0;
411 const double oneSigmaCoverage = 0.682689492137085897;
413 histo_, signal, signalFraction_, nIntegrationPoints_,
414 2.0*minimumBgFeatureSize_, initApprox, lenApprox,
415 workspace_)/oneSigmaCoverage;
416 if (nbg2 > maxBgEventsInWindow_)
417 maxBgEventsInWindow_ = nbg2;
419 winBgEvents = maxBgEventsInWindow_;
422 if (refitBandwidth_ || refitPolyDegree_)
425 const unsigned beVerboseFor = 3U;
426 const bool verboseRefit = verbose_ && callCount_ < beVerboseFor;
427 if (verbose_ && beVerboseFor && callCount_ == beVerboseFor)
428 std::cout <<
"**** MinuitLOrPEBgCVFcn1D appears to work "
429 <<
"fine and will shut up now" << std::endl;
432 histo_, fbuilder_, signal, signalFraction_,
433 nIntegrationPoints_, initApprox, lenApprox,
434 m_, minimumBgFeatureSize_, winBgEvents,
435 convergenceEpsilon_, maxIterations_,
436 bm_, useLeastSquaresCV_,
437 verboseRefit, !refitBandwidth_, cvmode_,
438 regularizationParameter_, minlog_, upNonparametric_);
443 const bool scanBandwidth = refitBandwidth_ && bandwidth_ <= 0.0;
444 const bool scanPolyDeg = refitPolyDegree_ && maxDegree_ < 0.0;
445 double bwstep = 0.0, degstep = 0.0;
447 if (scanBandwidth && scanPolyDeg)
448 scanBandwidthAndDegree(bgFcn, bandwidthScanPoints_,
449 winBgEvents, &bandwidth_, &bwstep,
450 &maxDegree_, °step);
451 else if (scanBandwidth)
452 scanBandwidthOnly(bgFcn, bandwidthScanPoints_,
453 winBgEvents, maxDegree_,
454 &bandwidth_, &bwstep);
455 else if (scanPolyDeg)
456 scanPolyDegOnly(bgFcn, winBgEvents,
457 bandwidth_, &maxDegree_, °step);
459 if (!refitBandwidthAndDegree(bgFcn, nFitCycles_, winBgEvents,
460 !refitBandwidth_, !refitPolyDegree_,
462 &maxDegree_, degstep))
467 if (!(refitBandwidth_ && refitPolyDegree_))
468 throw std::runtime_error(
469 "In npsi::MinuitSemiparametricFitFcn1D::operator()"
470 ": Minuit2 failed to optimize cross-validation "
471 "bandwidth or poly degree");
473 if (!(scanBandwidth && scanPolyDeg))
478 scanBandwidthAndDegree(bgFcn, bandwidthScanPoints_,
480 &bandwidth_, &bwstep,
481 &maxDegree_, °step);
487 refitBandwidthAndDegree(bgFcn, nFitCycles_, winBgEvents,
491 &maxDegree_, degstep);
497 histo_, fbuilder_, bm_, signal, signalFraction_,
498 nIntegrationPoints_, initApprox, lenApprox, m_,
499 bandwidth_, maxDegree_,
500 convergenceEpsilon_, maxIterations_,
501 &signalDensityBuffer_[0], signalDensityBuffer_.size(),
502 &bgDensityBuffer_[0], bgDensityBuffer_.size(), workspace_);
504 if (niter >= maxIterations_)
throw std::runtime_error(
505 "In npsi::MinuitSemiparametricFitFcn1D::operator(): "
506 "background determination algorithm failed to converge");
508 if (regularizationParameter_ >= 0.0)
510 const double nBg = nEvents_*(1.0 - signalFraction_);
511 const double minBgDensity1 = npstat::symbetaWeightAt0(
512 m_, bandwidth_)/nBg/std::pow(nBg, regularizationParameter_);
514 histo_, signalFraction_,
515 &signalDensityBuffer_[0], signalDensityBuffer_.size(),
516 &bgDensityBuffer_[0], bgDensityBuffer_.size(),
521 histo_, signalFraction_,
522 &signalDensityBuffer_[0], signalDensityBuffer_.size(),
523 &bgDensityBuffer_[0], bgDensityBuffer_.size(), minlog_);
527 std::cout <<
"C " << callCount_
528 <<
", bw " << bandwidth_
529 <<
", deg " << maxDegree_
530 <<
", sf " << signalFraction_;
535 std::cout <<
", m " << s->
location()
536 <<
", s " << s->
scale();
537 std::cout <<
", ll " << logli;
538 if (regularizationParameter_ >= 0.0)
539 std::cout <<
", adj " << numRegularized_;
551 inline double estimateMaxBandwidth()
const
555 return bwfactor*(axis.max() - axis.
min())*bandwidthLimitFactor_;
562 inline unsigned maxFilterDegree1D(
const double nbg)
const
564 if (polyDegreeLimit_ >= 0)
565 return polyDegreeLimit_;
569 lim += (lim/2U + 1U);
578 void scanPolyDegOnly(
const MinuitLOrPEBgCVFcn1D<Numeric,NumIn>& bgFcn,
579 const double effBgEvents,
const double bw,
580 double* bestDegree,
double* stepSize)
const
582 const unsigned nIntervalsOnUnit = 4U;
588 const unsigned maxDeg = maxFilterDegree1D(effBgEvents);
589 const double degstep = 1.0/nIntervalsOnUnit;
591 std::vector<double> arg(2);
594 bgFcn.getFilterProvider().startMemoizing();
596 double minFCN = DBL_MAX, bestdeg = 0.0;
597 for (
unsigned ideg=0U; ideg<=maxDeg; ++ideg)
599 const unsigned nInt = ideg == maxDeg ? 1U : nIntervalsOnUnit;
600 for (
unsigned iint=0U; iint<nInt; ++iint)
602 arg[1] = iint*degstep + ideg;
603 const double f = bgFcn(arg);
612 bgFcn.getFilterProvider().stopMemoizing();
614 *bestDegree = bestdeg;
618 void scanBandwidthOnly(
619 const MinuitLOrPEBgCVFcn1D<Numeric,NumIn>& bgFcn,
620 const unsigned bwScanPoints,
const double effBgEvents,
621 const double maxdeg,
double* bestBandwidth,
double* logStep)
const
623 assert(bwScanPoints > 1U);
624 assert(maxdeg >= 0.0);
625 assert(bestBandwidth);
628 const double maxRatio = estimateMaxBandwidth()/
629 minHistoBandwidth1D(histo_, minimumBgFeatureSize_,
630 0.0, effBgEvents, m_);
631 const double logstep = log(maxRatio)/(bwScanPoints - 1U);
632 std::vector<double> arg(2);
635 bgFcn.getFilterProvider().startMemoizing();
637 double minFCN = DBL_MAX, bestbw = 0.0;
638 for (
unsigned ibw=0U; ibw<bwScanPoints; ++ibw)
640 arg[0] = ibw*logstep;
641 const double f = bgFcn(arg);
649 bgFcn.getFilterProvider().stopMemoizing();
651 *bestBandwidth = bgFcn.getActualBandwidth(bestbw, maxdeg);
655 void scanBandwidthAndDegree(
656 const MinuitLOrPEBgCVFcn1D<Numeric,NumIn>& bgFcn,
657 const unsigned bwScanPoints,
const double effBgEvents,
658 double* p_bandwidth,
double* p_bwstep,
659 double* p_maxDegree,
double* p_degstep)
const
661 const unsigned nIntervalsOnUnit = 4U;
667 assert(bwScanPoints > 1U);
668 assert(refitBandwidth_);
670 const unsigned maxDeg = maxFilterDegree1D(effBgEvents);
671 const double degstep = 1.0/nIntervalsOnUnit;
672 const double maxRatio = estimateMaxBandwidth()/
673 minHistoBandwidth1D(histo_, minimumBgFeatureSize_,
674 0.0, effBgEvents, m_);
675 const double logstep = log(maxRatio)/(bwScanPoints - 1U);
676 std::vector<double> arg(2);
678 bgFcn.getFilterProvider().startMemoizing();
680 double minFCN = DBL_MAX;
681 for (
unsigned ideg=0U; ideg<=maxDeg; ++ideg)
683 const unsigned nInt = ideg == maxDeg ? 1U : nIntervalsOnUnit;
684 for (
unsigned iint=0U; iint<nInt; ++iint)
686 arg[1] = iint*degstep + ideg;
687 for (
unsigned ibw=0U; ibw<bwScanPoints; ++ibw)
689 arg[0] = ibw*logstep;
690 const double f = bgFcn(arg);
694 *p_bandwidth = arg[0];
695 *p_maxDegree = arg[1];
701 bgFcn.getFilterProvider().stopMemoizing();
703 *p_bandwidth = bgFcn.getActualBandwidth(*p_bandwidth, *p_maxDegree);
705 *p_degstep = degstep;
713 bool refitBandwidthAndDegree(
714 const MinuitLOrPEBgCVFcn1D<Numeric,NumIn>& bgFcn,
715 const unsigned ncycles,
const double effectiveBgEvents,
716 const bool fixBandwidth,
const bool fixPolyDegree,
717 double* p_bandwidth,
const double inBwstep,
718 double* p_maxDegree,
const double inDegstep)
const
723 double bw = *p_bandwidth;
724 double deg = *p_maxDegree;
727 const double degreeLimit = maxFilterDegree1D(effectiveBgEvents);
732 if (deg > degreeLimit)
737 const double minBandwidth = minHistoBandwidth1D(
738 histo_, minimumBgFeatureSize_, deg, effectiveBgEvents, m_);
739 const double maxRatio = estimateMaxBandwidth()/
740 minHistoBandwidth1D(histo_, minimumBgFeatureSize_,
741 0.0, effectiveBgEvents, m_);
747 throw std::invalid_argument(
748 "In npsi::MinuitSemiparametricFitFcn1D::"
749 "refitBandwidthAndDegree: minimum bandwidth is too "
750 "large (or maximum is too small)");
752 const double maxBandwidth = minBandwidth*maxRatio;
753 const double limFactor = 1.00001;
755 if (bw < minBandwidth*limFactor)
756 bw = minBandwidth*limFactor;
757 if (bw > maxBandwidth/limFactor)
758 bw = maxBandwidth/limFactor;
760 bw = log(bw/minBandwidth);
765 const double precision = crossValidationPrecision();
766 for (
unsigned itry=0; itry<5U; ++itry)
768 const double errfactor = pow(1.4, itry);
769 const double precfactor = pow(10.0, itry);
772 ROOT::Minuit2::MnUserParameters upar;
774 upar.Add(
"bandwidth", bw, 0.1);
777 const double bwstep = inBwstep > 0.0 ?
778 inBwstep : 0.1*errfactor;
779 upar.Add(
"bandwidth", bw, bwstep, 0.0, log(maxRatio));
782 upar.Add(
"degree", deg, 0.1);
785 const double degstep = inDegstep > 0.0 ?
786 inDegstep : 0.1*errfactor;
787 upar.Add(
"degree", deg, degstep, 0.0, degreeLimit);
791 ROOT::Minuit2::MnMinimize mini(bgFcn, upar);
792 mini.SetPrecision(precision*precfactor);
796 else if (fixPolyDegree)
803 for (
unsigned icycle=0; icycle<ncycles; ++icycle)
815 ROOT::Minuit2::FunctionMinimum fit(mini());
818 *p_maxDegree = mini.Value(1U);
820 *p_bandwidth = mini.Value(0U);
822 *p_bandwidth = bgFcn.getActualBandwidth(mini.Value(0U),
831 mutable std::vector<double> signalParameters_;
832 mutable std::vector<double> signalDensityBuffer_;
833 mutable std::vector<double> bgDensityBuffer_;
834 mutable std::vector<double> workspace_;
838 const DensityConstructor& densityMaker_;
839 std::vector<NumIn> initialApproximation_;
841 double minimumBgFeatureSize_;
842 double convergenceEpsilon_;
843 double pseudoFitPrecision_;
844 mutable double bandwidth_;
845 mutable double maxDegree_;
846 mutable double signalFraction_;
849 double upNonparametric_;
850 double regularizationParameter_;
851 double bandwidthLimitFactor_;
853 mutable double maxBgEventsInWindow_;
855 mutable unsigned long callCount_;
856 unsigned nIntegrationPoints_;
857 unsigned maxIterations_;
858 unsigned nFitCycles_;
859 int polyDegreeLimit_;
861 unsigned bandwidthScanPoints_;
863 mutable unsigned numRegularized_;
867 bool refitBandwidth_;
868 bool refitPolyDegree_;
870 bool useLeastSquaresCV_;
Fit of LOrPE bandwidth and maximum poly degree in the mixed signal/background model.
Definition: MinuitLOrPEBgCVFcn1D.hh:28
Definition: MinuitSemiparametricFitFcn1D.hh:50
virtual double operator()(const std::vector< double > &x) const
Definition: MinuitSemiparametricFitFcn1D.hh:362
MinuitSemiparametricFitFcn1D(const npstat::HistoND< Numeric > &histo, const DensityConstructor &densityMaker, npstat::AbsSymbetaFilterProvider &fb, const npstat::BoundaryHandling &bm, const int symmetricBetaPower, const double minimumBgFeatureSize, const NumIn *initialApproximation=0, const unsigned lenApproximation=0U, const int polyDegreeLimit=-1, const bool verbose=true, const unsigned cvmode=npstat::CV_MODE_LINEARIZED, const bool useLeastSquaresCV=true, const bool refitBandwidth=true, const bool refitPolyDegree=true, const double regularizationParameter=-1.0, const unsigned nIntegrationPoints=0U, const double bandwidthUpperLimitFactor=5.0, const unsigned pseudoFitCycles=0U, const double convergenceEpsilon=0.0, const double pseudoFitPrecision=0.0, const unsigned bandwidthScanPoints=64U, const double minlog=log(DBL_MIN), const double up=0.5, const double upRefit=0.05, const unsigned maxIterations=10000U)
Definition: MinuitSemiparametricFitFcn1D.hh:209
unsigned lastRegularized() const
Definition: MinuitSemiparametricFitFcn1D.hh:310
Definition: AbsDistribution1D.hh:165
double scale() const
Definition: AbsDistribution1D.hh:183
double location() const
Definition: AbsDistribution1D.hh:180
Definition: AbsSymbetaFilterProvider.hh:28
Definition: BoundaryHandling.hh:21
Definition: HistoAxis.hh:31
double min() const
Definition: HistoAxis.hh:42
Definition: HistoND.hh:46
unsigned long nBins() const
Definition: HistoND.hh:226
Definition: fitCompositeJohnson.hh:16
Definition: AbsArrayProjector.hh:14
double symbetaBandwidthRatio(int power, unsigned filterDegree)
unsigned amisePluginDegreeGauss(double npoints)
unsigned maxFilterDegreeSupported()
unsigned lorpeRegularizeBgDensity1D(const HistoND< Numeric > &histo, double signalFraction, const NumOut *signalDensity, unsigned lenSignalDensity, NumOut *bgDensity, unsigned lenBgDensity, double minBgDensity1)
double maxBgPointsInWindow1D(const HistoND< Numeric > &histo, const AbsDistribution1D &signal, double signalFraction, unsigned nIntegrationPoints, double windowWidth, const NumIn *initialApproximation, unsigned lenApproximation, std::vector< double > &workspace)
unsigned amisePluginDegreeSymbeta(unsigned power, double npoints)
double lorpeBgLogli1D(const HistoND< Numeric > &histo, double signalFraction, const NumOut *signalDensity, unsigned lenSignalDensity, const NumOut *bgDensity, unsigned lenBgDensity, double minlog=log(DBL_MIN))
unsigned lorpeBackground1D(const HistoND< Numeric > &histo, AbsSymbetaFilterProvider &fbuilder, const BoundaryHandling &bm, const AbsDistribution1D &signal, double signalFraction, unsigned nIntegrationPoints, const NumIn *initialApproximation, unsigned lenApproximation, int m, double bandwidth, double maxDegree, double convergenceEpsilon, unsigned maxIterations, NumOut *signalDensity, unsigned lenSignalDensity, NumOut *bgDensity, unsigned lenBgDensity, std::vector< double > &workspace, NumOut *densityMinusOne=0, unsigned lenDensityMinusOne=0, unsigned cvmode=CV_MODE_LINEARIZED, double regularizationParameter=-1.0, double *lastDivergence=0)
Definition: AbsDistribution1D.hh:31