Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
Asymptotics.cxx
Go to the documentation of this file.
1#include "xRooFit/xRooFit.h"
2
3#include <cmath>
4#include "Math/ProbFunc.h"
7
9
11
12Double_t xRooFit::Asymptotics::k(const IncompatFunc &compatRegions, double pValue, double poiVal, double poiPrimeVal,
13 double sigma, double low, double high)
14{
15
16 // determine the pll value corresponding to nSigma expected - i.e. where the altPValue equals e.g. 50% for nSigma=0,
17 // find the solution (wrt x) of: FitManager::altPValue(x, var(poi), alt_val, _sigma_mu, _compatibilityFunction) -
18 // targetPValue = 0
19 double targetTailIntegral = pValue; // ROOT::Math::normal_cdf(*nSigma);
20
21 // check how much of the alt distribution density is in the delta function @ 0
22 // if more than 1 - target is in there, if so then pll must be 0
23 double prob_in_delta = Phi_m(poiVal, poiPrimeVal, std::numeric_limits<double>::infinity(), sigma, compatRegions);
24 // also get a contribution to the delta function for mu_hat < mu_L IF mu==mu_L
25 if (poiVal == low) {
26 // since mu_hat is gaussian distributed about mu_prime with std-dev = sigma
27 // the integral is Phi( mu_L - mu_prime / (sigma) )
28 double mu_L = low;
29 prob_in_delta += ROOT::Math::normal_cdf((mu_L - poiPrimeVal) / sigma);
30 }
31
32 if (prob_in_delta > 1 - targetTailIntegral) {
33 return 0;
34 }
35
36 struct TailIntegralFunction {
37 TailIntegralFunction(double _poiVal, double _alt_val, double _sigma_mu, double _low, double _high,
38 IncompatFunc _compatibilityFunction, double _target)
39 : poiVal(_poiVal), alt_val(_alt_val), sigma_mu(_sigma_mu), low(_low), high(_high), target(_target),
40 cFunc(_compatibilityFunction)
41 {
42 }
43
44 double operator()(double x) const
45 {
46 double val = PValue(cFunc, x, poiVal, alt_val, sigma_mu, low, high);
47 if (val < 0)
48 kInvalid = true;
49 return val - target;
50 }
51
52 double poiVal, alt_val, sigma_mu, low, high, target;
53 IncompatFunc cFunc;
54 mutable bool kInvalid = false;
55 };
56
57 TailIntegralFunction f(poiVal, poiPrimeVal, sigma, low, high, compatRegions, targetTailIntegral);
60
61 auto tmpLvl = gErrorIgnoreLevel;
63 double _pll = 500.;
64 double currVal(1.);
65 int tryCount(0);
66 double _prev_pll = _pll;
67 do {
68 currVal = wf(_pll);
69 if (currVal > 1e-4)
70 _pll = 2. * (_pll + 1.); // goto bigger pll scale
71 else if (currVal < -1e-4)
72 _pll /= 2.; // goto smaller pll scale
73 // std::cout << "pll = " << _pll << " currVal = " << currVal << std::endl;
74 brf.SetFunction(wf, 0, _pll);
75 if (brf.Solve()) {
76 _prev_pll = _pll;
77 _pll = brf.Root();
78 }
79 if (f.kInvalid) { // happens if problem evaluating PValue (e.g. sigma was nan)
80 _pll = std::numeric_limits<double>::quiet_NaN();
81 break;
82 }
83 // std::cout << " -- " << brf.Root() << " " << FitManager::altPValue(_pll, mu, alt_val, sigma, pllModifier()) << "
84 // >> " << wf(_pll) << std::endl;
85 tryCount++;
86 if (tryCount > 20) {
87 gErrorIgnoreLevel = tmpLvl;
88 Warning("Asymptotics::k", "Reached limit pValue=%g pll=%g", pValue, _pll);
89 break;
90 }
91 } while (std::abs(wf(_pll)) > 1e-4 && std::abs(wf(_pll)) < std::abs(wf(_prev_pll)) * 0.99);
92 gErrorIgnoreLevel = tmpLvl;
93 return _pll;
94}
95
96Double_t xRooFit::Asymptotics::PValue(const IncompatFunc &compatRegions, double k, double poiVal, double poi_primeVal,
97 double sigma, double lowBound, double upBound)
98{
99 // uncapped test statistic is equal to onesidednegative when k is positive, and equal to 1.0 - difference between
100 // twosided and onesidednegative when k is negative ...
101 if (compatRegions == IncompatibilityFunction(Uncapped, poiVal)) {
102 // if(k==0) return 0.5;
103 if (k > 0)
104 return PValue(OneSidedNegative, k, poiVal, poi_primeVal, sigma, lowBound, upBound);
105 return 1. - (PValue(TwoSided, -k, poiVal, poi_primeVal, sigma, lowBound, upBound) -
106 PValue(OneSidedNegative, -k, poiVal, poi_primeVal, sigma, lowBound, upBound));
107 }
108
109 // if(k<0) return 1.;
110 if (k <= 0) {
111 if (compatRegions == IncompatibilityFunction(OneSidedNegative, poiVal) && std::abs(poiVal - poi_primeVal) < 1e-9)
112 return 0.5; // when doing discovery (one-sided negative) use a 0.5 pValue
113 return 1.; // case to catch the delta function that ends up at exactly 0 for the one-sided tests
114 }
115
116 if (sigma == 0) {
117 if (lowBound != -std::numeric_limits<double>::infinity() || upBound != std::numeric_limits<double>::infinity()) {
118 return -1;
119 } else if (std::abs(poiVal - poi_primeVal) > 1e-12) {
120 return -1;
121 }
122 }
123
124 // get the poi value that defines the test statistic, and the poi_prime hypothesis we are testing
125 // when setting limits, these are often the same value
126
127 Double_t Lambda_y = 0;
128 if (std::abs(poiVal - poi_primeVal) > 1e-12)
129 Lambda_y = (poiVal - poi_primeVal) / sigma;
130
131 if (std::isnan(Lambda_y))
132 return -1;
133
134 Double_t k_low = (lowBound == -std::numeric_limits<double>::infinity()) ? std::numeric_limits<double>::infinity()
135 : pow((poiVal - lowBound) / sigma, 2);
136 Double_t k_high = (upBound == std::numeric_limits<double>::infinity()) ? std::numeric_limits<double>::infinity()
137 : pow((upBound - poiVal) / sigma, 2);
138
139 double out = Phi_m(poiVal, poi_primeVal, std::numeric_limits<double>::infinity(), sigma, compatRegions) - 1;
140
141 if (out < -1) {
142 // compatibility function is unsupported, return negative
143 return -2;
144 }
145
146 // go through the 4 'regions' ... only two of which will apply
147 if (k <= k_high) {
148 out += ROOT::Math::gaussian_cdf(sqrt(k) + Lambda_y) -
149 Phi_m(poiVal, poi_primeVal, Lambda_y + sqrt(k), sigma, compatRegions);
150 } else {
151 double Lambda_high = (poiVal - upBound) * (poiVal + upBound - 2. * poi_primeVal) / (sigma * sigma);
152 double sigma_high = 2. * (upBound - poiVal) / sigma;
153 out += ROOT::Math::gaussian_cdf((k - Lambda_high) / sigma_high) -
154 Phi_m(poiVal, poi_primeVal, (k - Lambda_high) / sigma_high, sigma, compatRegions);
155 }
156
157 if (k <= k_low) {
158 out += ROOT::Math::gaussian_cdf(sqrt(k) - Lambda_y) +
159 Phi_m(poiVal, poi_primeVal, Lambda_y - sqrt(k), sigma, compatRegions);
160 } else {
161 double Lambda_low = (poiVal - lowBound) * (poiVal + lowBound - 2. * poi_primeVal) / (sigma * sigma);
162 double sigma_low = 2. * (poiVal - lowBound) / sigma;
163 out += ROOT::Math::gaussian_cdf((k - Lambda_low) / sigma_low) +
164 Phi_m(poiVal, poi_primeVal, (Lambda_low - k) / sigma_low, sigma, compatRegions);
165 /*out += ROOT::Math::gaussian_cdf((k-Lambda_low)/sigma_low) +
166 2*Phi_m(poiVal,poi_primeVal,(Lambda_low - k_low)==0 ? 0 : ((Lambda_low -
167 k_low)/sigma_low),sigma,compatRegions)
168 - Phi_m(poiVal,poi_primeVal,(Lambda_low - k)/sigma_low,sigma,compatFunc);
169*/
170
171 // handle case where poiVal = lowBound (e.g. testing mu=0 when lower bound is mu=0).
172 // sigma_low will be 0 and gaussian_cdf will end up being 1, but we need it to converge instead
173 // to 0.5 so that pValue(k=0) converges to 1 rather than 0.5.
174 // handle this by 'adding' back in the lower bound
175 // TODO: Think more about this?
176 /*if (sigma_low == 0) {
177 out -= 0.5;
178 }*/
179 }
180
181 return 1. - out;
182}
183
185xRooFit::Asymptotics::Phi_m(double /*mu*/, double mu_prime, double a, double sigma, const IncompatFunc &compatRegions)
186{
187
188 if (sigma == 0)
189 sigma = 1e-100; // avoid nans if sigma is 0
190
191 // want to evaluate gaussian integral in regions where IncompatFunc = 0
192
193 double out = 0;
194 double lowEdge = std::numeric_limits<double>::quiet_NaN();
195 for (auto &transition : compatRegions) {
196 if (transition.first >= (a * sigma + mu_prime))
197 break;
198 if (transition.second == 0 && std::isnan(lowEdge))
199 lowEdge = transition.first;
200 else if (!std::isnan(lowEdge)) {
201 out += ROOT::Math::gaussian_cdf((transition.first - mu_prime) / sigma) -
202 ROOT::Math::gaussian_cdf((lowEdge - mu_prime) / sigma);
203 lowEdge = std::numeric_limits<double>::quiet_NaN();
204 }
205 }
206 if (!std::isnan(lowEdge)) { // also catches case where last transition is before a
207 out += ROOT::Math::gaussian_cdf(a) - ROOT::Math::gaussian_cdf((lowEdge - mu_prime) / sigma);
208 }
209
210 return out;
211}
212
213int xRooFit::Asymptotics::CompatFactor(const IncompatFunc &func, double mu_hat)
214{
215 if (std::isnan(mu_hat))
216 return 1; // nan is never compatible
217 int out = 1;
218 for (auto &transition : func) {
219 if (transition.first > mu_hat)
220 break;
221 out = transition.second;
222 }
223 return out;
224}
225
226// RooRealVar xRooFit::Asymptotics::FindLimit(TGraph* pVals, double target_pVal) {
227// auto target_sig = RooStats::PValueToSignificance(target_pVal);
228// TGraph sig;
229// for(int i=0;i<pVals->GetN();i++) {
230// sig.SetPoint(i,pVals->GetPointX(i),RooStats::PValueToSignificance(pVals->GetPointY(i))-target_sig);
231// }
232// sig.Sort(); // ensure points are in x order
233// // now loop over and find where function crosses zero
234// for(int i=0;i<sig.GetN();i++) {
235// if (sig.GetPointY(i)>=0) {
236// if (i==0) return RooRealVar("limit","limit",std::numeric_limits<double>::quiet_NaN());
237// double prev_x = sig.GetPointX(i-1);
238// double next_x = sig.GetPointX(i);
239// double prev_y = sig.GetPointY(i-1);
240// double next_y = sig.GetPointY(i);
241// return RooRealVar("limit","limit", prev_x + (next_x-prev_x)*(-prev_y)/(next_y-prev_y));
242// }
243// }
244// return RooRealVar("limit","limit",std::numeric_limits<double>::quiet_NaN());
245// }
246
#define f(i)
Definition RSha256.hxx:104
#define a(i)
Definition RSha256.hxx:99
#define e(i)
Definition RSha256.hxx:103
double Double_t
Definition RtypesCore.h:59
const Int_t kFatal
Definition TError.cxx:41
Int_t gErrorIgnoreLevel
Definition TError.cxx:43
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:241
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
TRObject operator()(const T1 &t1) const
@ kInvalid
Definition TSystem.h:79
Class for finding the root of a one dimensional function using the Brent algorithm.
bool SetFunction(const ROOT::Math::IGenFunction &f, double xlow, double xup) override
Sets the function for the rest of the algorithms.
bool Solve(int maxIter=100, double absTol=1E-8, double relTol=1E-10) override
Returns the X value corresponding to the function value fy for (xmin<x<xmax).
double Root() const override
Returns root value.
Template class to wrap any C++ callable object which takes one argument i.e.
std::vector< std::pair< double, int > > IncompatFunc
Definition xRooFit.h:93
double normal_cdf(double x, double sigma=1, double x0=0)
Cumulative distribution function of the normal (Gaussian) distribution (lower tail).
RVec< PromoteTypes< T0, T1 > > pow(const T0 &x, const RVec< T1 > &v)
Definition RVec.hxx:1794
const Double_t sigma
Double_t x[n]
Definition legend1.C:17
double gaussian_cdf(double x, double sigma=1, double x0=0)
Alternative name for same function.
VecExpr< UnaryOp< Sqrt< T >, VecExpr< A, T, D >, T >, T, D > sqrt(const VecExpr< A, T, D > &rhs)
#define BEGIN_XROOFIT_NAMESPACE
Definition Config.h:24
#define END_XROOFIT_NAMESPACE
Definition Config.h:25