herwig is hosted by Hepforge, IPPP Durham
Herwig 7.3.0
RandomHelpers.h
1// -*- C++ -*-
2//
3// RandomHelpers.h is a part of Herwig - A multi-purpose Monte Carlo event generator
4// Copyright (C) 2002-2019 The Herwig Collaboration
5//
6// Herwig is licenced under version 3 of the GPL, see COPYING for details.
7// Please respect the MCnet academic guidelines, see GUIDELINES for details.
8//
9#ifndef HERWIG_RandomHelpers_H
10#define HERWIG_RandomHelpers_H
11
13
14namespace Herwig {
15
16using namespace ThePEG;
17
23namespace RandomHelpers {
24
30inline double sign(double x) {
31 return x < 0. ? -1. : 1.;
32}
33
39template<class Density>
40struct Generator {
41
45 double lower() const;
46
50 double upper() const;
51
55 double value(double x) const;
56
60 double normalization() const;
61
66 double operator()(double r) const;
67
68};
69
75struct Expression {};
76
82template<>
84
88 virtual ~Generator() {}
89
93 virtual double lower() const = 0;
94
98 virtual double upper() const = 0;
99
103 virtual double value(double x) const = 0;
104
108 virtual double normalization() const = 0;
109
114 virtual double operator()(double r) const = 0;
115
116};
117
123template<class Density>
124struct Container {};
125
131template<class Density>
132class Generator<Container<Density> >
133 : public Generator<Expression> {
134
139
140public:
141
146 : generator(gen) {}
147
151 virtual double lower() const { return generator.lower(); }
152
156 virtual double upper() const { return generator.upper(); }
157
161 virtual double value(double x) const { return generator.value(x); }
162
166 virtual double normalization() const { return generator.normalization(); }
167
172 virtual double operator()(double r) const { return generator(r); }
173
174};
175
181template<class Density>
182pair<double,double> generate(const Generator<Density>& gen,
183 double r) {
184 double x = gen(r);
185
186 if ( gen.value(x) != 0. )
187 return make_pair(x,gen.normalization()/gen.value(x));
188 else
189 return make_pair(x,0.);
190}
191
197template<class Density>
198struct Remap {};
199
205template<class Density>
206class Generator<Remap<Density> > {
207
212
216 double theLower;
217
221 double theUpper;
222
227 double low, double up)
228 : theGenerator(gen), theLower(low), theUpper(up) {
229 if ( low >= up )
230 throw std::logic_error("[Generator<Remap>] Invalid boundaries.");
231 }
232
236 const Generator<Density>& generator() const { return theGenerator; }
237
241 double lower() const { return theLower; }
242
246 double upper() const { return theUpper; }
247
251 double value(double y) const {
252 double xm = generator().lower();
253 double xp = generator().upper();
254 double ym = lower();
255 double yp = upper();
256 double x = ((xp-xm)/(yp-ym))*y+(yp*xm-ym*xp)/(yp-ym);
257 return generator().value(x);
258 }
259
263 double normalization() const {
264 double xm = generator().lower();
265 double xp = generator().upper();
266 double ym = lower();
267 double yp = upper();
268 return ((yp-ym)/(xp-xm))*generator().normalization();
269 }
270
275 double operator()(double r) const {
276 double xm = generator().lower();
277 double xp = generator().upper();
278 double ym = lower();
279 double yp = upper();
280 double x = ((yp-ym)/(xp-xm))*generator()(r)+(xp*ym-xm*yp)/(xp-xm);
281 return x;
282 }
283
284};
285
291struct on {
292
296 double lower;
297
301 double upper;
302
306 on(double a, double b)
307 :lower(a), upper(b) {}
308};
309
315template<class Density>
317 const on& interval) {
318 return Generator<Remap<Density> >(gen,interval.lower,interval.upper);
319}
320
321
327template<class Density>
328struct Rescale {};
329
335template<class Density>
336class Generator<Rescale<Density> > {
337
342
346 double theScale;
347
348public:
349
354 double sc)
355 : theGenerator(gen), theScale(sc) {
356 }
357
361 const Generator<Density>& generator() const { return theGenerator; }
362
366 double scale() const { return theScale; }
367
371 double lower() const { return generator().lower(); }
372
376 double upper() const { return generator().upper(); }
377
381 double value(double x) const {
382 return scale()*generator().value(x);
383 }
384
388 double normalization() const {
389 return scale()*generator().normalization();
390 }
391
396 double operator()(double r) const {
397 return generator()(r);
398 }
399
400};
401
407template<class Density>
409 return Generator<Rescale<Density> >(gen,a);
410}
411
417template<class Density1,
418 class Density2>
419struct Sum {};
420
426template<class Density1,
427 class Density2>
428class Generator<Sum<Density1,Density2> > {
429
434
439
443 double theLower;
444
448 double theUpper;
449
455
456public:
457
462 const Generator<Density2>& secondGen)
463 : theFirstGenerator(firstGen), theSecondGenerator(secondGen),
464 theLower(min(firstGen.lower(),secondGen.lower())),
465 theUpper(max(firstGen.upper(),secondGen.upper())),
466 theFraction(1.) {
467 theFraction =
468 firstGenerator().normalization() / normalization();
469 }
470
474 const Generator<Density1>& firstGenerator() const { return theFirstGenerator; }
475
479 const Generator<Density2>& secondGenerator() const { return theSecondGenerator; }
480
484 double lower() const { return theLower; }
485
489 double upper() const { return theUpper; }
490
495 double fraction() const { return theFraction; }
496
500 double value(double x) const {
501 double res = 0.;
502 if ( firstGenerator().lower() <= x &&
503 x <= firstGenerator().upper() )
504 res += firstGenerator().value(x);
505 if ( secondGenerator().lower() <= x &&
506 x <= secondGenerator().upper() )
507 res += secondGenerator().value(x);
508 return res;
509 }
510
514 double normalization() const {
515 return
516 firstGenerator().normalization() + secondGenerator().normalization();
517 }
518
523 double operator()(double r) const {
524 return
525 r < fraction() ?
526 firstGenerator()(r/fraction()) :
527 secondGenerator()((r-fraction())/(1.-fraction()));
528 }
529
530};
531
537template<class Density1,
538 class Density2>
540 const Generator<Density2>& second) {
541 return Generator<Sum<Density1,Density2> >(first,second);
542}
543
550template<class Density>
551struct matcher {
552
557
562 : generator(gen) {}
563
564};
565
572template<class Density>
574 return matcher<Density>(gen);
575}
576
583template<class Density1,
584 class Density2>
586 const matcher<Density2>& second) {
587 double matching =
588 first.value(first.upper())/
589 second.generator.value(second.generator.lower());
590 return Generator<Sum<Density1,Rescale<Density2> > >(first,matching*second.generator);
591}
592
598template<class Density1,
599 class Density2>
600struct Piecewise {};
601
607struct ToBeDefined {};
608
614template<class Density1,
615 class Density2>
616class Generator<Piecewise<Density1,Density2> > {
617
622
627
631 double theLower;
632
637
641 double theUpper;
642
648
649public:
650
655 const Generator<Density2>& secondGen)
656 : theFirstGenerator(firstGen), theSecondGenerator(secondGen),
657 theLower(firstGen.lower()), theIntermediate(firstGen.upper()), theUpper(secondGen.upper()),
658 theFraction(1.) {
659 if ( firstGenerator().upper() != secondGenerator().lower() )
660 throw std::logic_error("[Generator<Piecewise>] Invalid boundaries.");
661 theFraction =
662 firstGenerator().normalization() / normalization();
663 }
664
668 const Generator<Density1>& firstGenerator() const { return theFirstGenerator; }
669
673 const Generator<Density2>& secondGenerator() const { return theSecondGenerator; }
674
678 double lower() const { return theLower; }
679
683 double intermediate() const { return theIntermediate; }
684
688 double upper() const { return theUpper; }
689
694 double fraction() const { return theFraction; }
695
699 double value(double x) const {
700 return
701 x < intermediate() ?
702 firstGenerator().value(x) :
703 secondGenerator().value(x);
704 }
705
709 double normalization() const {
710 return
711 firstGenerator().normalization() + secondGenerator().normalization();
712 }
713
718 double operator()(double r) const {
719 return
720 r < fraction() ?
721 firstGenerator()(r/fraction()) :
722 secondGenerator()((r-fraction())/(1.-fraction()));
723 }
724
728 template<class Density3>
730 operator,(const Generator<Density3>& thirdGenerator) {
731 return
733 (*this,thirdGenerator);
734 }
735
739 template<class Density3>
741 operator,(const matcher<Density3>& thirdGenerator) {
742 double matching =
743 value(upper())/thirdGenerator.generator.value(upper());
744 return
746 (*this,matching*thirdGenerator.generator);
747 }
748
749};
750
756template<class Density>
757struct Generator<Piecewise<Density,ToBeDefined> > {
758
763
768 : generator(gen) {}
769
773 template<class Density2>
775 operator,(const Generator<Density2>& secondGen) {
776 return
778 (generator,secondGen);
779 }
780
784 template<class Density2>
786 operator,(const matcher<Density2>& secondGen) {
787 double matching =
788 generator.value(generator.upper())/secondGen.generator.value(generator.upper());
789 return
791 (generator,matching*secondGen.generator);
792 }
793
794};
795
801template<>
803
807 template<class Density>
810 return
812 }
813
814};
815
821inline Generator<Piecewise<ToBeDefined,ToBeDefined> >
824}
825
826
827
833struct Flat {};
834
840template<>
842
846 double theLower;
847
851 double theUpper;
852
853public:
854
858 Generator(double low, double up)
859 : theLower(low), theUpper(up) {}
860
864 double lower() const { return theLower; }
865
869 double upper() const { return theUpper; }
870
874 double value(double x) const {
875 return x>=lower() && x<=upper() ? 1. : 0.;
876 }
877
881 double normalization() const { return upper()-lower(); }
882
887 double operator()(double r) const {
888 return lower() + r*(upper()-lower());
889 }
890
891};
892
898inline Generator<Flat> flat(double low, double up) {
899 return Generator<Flat>(low,up);
900}
901
907struct Zero {};
908
914template<>
916
920 double theLower;
921
925 double theUpper;
926
927public:
928
932 Generator(double low, double up)
933 : theLower(low), theUpper(up) {}
934
938 double lower() const { return theLower; }
939
943 double upper() const { return theUpper; }
944
948 double value(double x) const {
949 return x>=lower() && x<=upper() ? Constants::epsilon : 0.;
950 }
951
955 double normalization() const { return 0.; }
956
961 double operator()(double r) const {
962 return lower() + r*(upper()-lower());
963 }
964
965};
966
972inline Generator<Zero> zero(double low, double up) {
973 return Generator<Zero>(low,up);
974}
975
981struct Inverse {};
982
988template<>
990
994 double thePole;
995
999 double theLower;
1000
1004 double theUpper;
1005
1009 double theScale;
1010
1015
1016public:
1017
1021 Generator(double z,
1022 double l, double u)
1023 : thePole(z),
1024 theLower(l), theUpper(u),
1025 theScale(z < l ? log((u-z)/(l-z)) : log((z-l)/(z-u))),
1026 theOffset(z < l ? log(l-z) : log(z-u)) {
1027 if ( z >= l && z <= u )
1028 throw std::logic_error("[Generator<Inverse>] Pole inside sampling interval.");
1029 }
1030
1034 double lower() const { return theLower; }
1035
1039 double upper() const { return theUpper; }
1040
1044 double pole() const { return thePole; }
1045
1049 double scale() const { return theScale; }
1050
1054 double offset() const { return theOffset; }
1055
1059 double value(double x) const {
1060 return x>=lower() && x<=upper() ? 1/abs(x-pole()) : 0.;
1061 }
1062
1066 double normalization() const {
1067 return scale();
1068 }
1069
1074 double operator()(double r) const {
1075 return pole() + sign(upper()-pole())*exp(scale()*r+offset());
1076 }
1077
1078};
1079
1086 double lower, double upper) {
1087 return Generator<Inverse>(z,lower,upper);
1088}
1089
1095struct Power {};
1096
1102template<>
1104
1108 double thePole;
1109
1113 double thePower;
1114
1118 double theLower;
1119
1123 double theUpper;
1124
1128 double theScale;
1129
1134
1135public:
1136
1140 Generator(double z, double p,
1141 double l, double u)
1142 : thePole(z), thePower(p),
1143 theLower(l), theUpper(u),
1144 theScale(z<=l ? (pow(u-z,1.+p)-pow(l-z,1.+p))/(1.+p) : (pow(z-l,1.+p)-pow(z-u,1.+p))/(1.+p)),
1145 theOffset(z<=l ? pow(l-z,1.+p)/(1.+p) : pow(z-u,1.+p)/(1.+p)) {
1146 if ( p == -1. )
1147 throw std::logic_error("[Generator<Power>] Unit inverse. Consider using inverse().");
1148 if ( z >= l && z <= u && p < 0. )
1149 throw std::logic_error("[Generator<Power>] Pole inside sampling interval.");
1150 if ( z >= l && z <= u && p > 0. )
1151 throw std::logic_error("[Generator<Power>] Zero inside sampling interval.");
1152 }
1153
1157 double lower() const { return theLower; }
1158
1162 double upper() const { return theUpper; }
1163
1167 double pole() const { return thePole; }
1168
1172 double power() const { return thePower; }
1173
1177 double scale() const { return theScale; }
1178
1182 double offset() const { return theOffset; }
1183
1187 double value(double x) const {
1188 return x>=lower() && x<=upper() ? pow(abs(x-pole()),power()) : 0.;
1189 }
1190
1194 double normalization() const {
1195 return scale();
1196 }
1197
1202 double operator()(double r) const {
1203 return pole() + sign(upper()-pole())*pow((1.+power())*(scale()*r+offset()),1./(1.+power()));
1204 }
1205
1206};
1207
1213inline Generator<Power> power(double z, double p,
1214 double lower, double upper) {
1215 return Generator<Power>(z,p,lower,upper);
1216}
1217
1223struct BreitWigner {};
1224
1230template<>
1232
1236 double thePole;
1237
1241 double theWidth;
1242
1246 double theLower;
1247
1251 double theUpper;
1252
1256 double theScale;
1257
1262
1267
1268public:
1269
1273 Generator(double z, double w,
1274 double l, double u)
1275 : thePole(z), theWidth(w),
1276 theLower(l), theUpper(u),
1277 theScale((atan((u-z)/sqrt(abs(w*z)))-atan((l-z)/sqrt(abs(w*z))))/sqrt(abs(w*z))),
1278 theOffset(atan((l-z)/sqrt(abs(w*z)))/sqrt(abs(w*z))),
1279 theSqrtWidth(sqrt(abs(w*z))) {
1280 if ( w == 0. )
1281 throw std::logic_error("[Generator<BreitWigner>] Zero width. Consider using power().");
1282 }
1283
1287 double lower() const { return theLower; }
1288
1292 double upper() const { return theUpper; }
1293
1297 double pole() const { return thePole; }
1298
1302 double width() const { return theWidth; }
1303
1307 double scale() const { return theScale; }
1308
1312 double offset() const { return theOffset; }
1313
1317 double sqrtWidth() const { return theSqrtWidth; }
1318
1322 double value(double x) const {
1323 return
1324 x>=lower() && x<=upper() ?
1325 1./(sqr(x-pole())+abs(width()*pole())) : 0.;
1326 }
1327
1331 double normalization() const {
1332 return scale();
1333 }
1334
1339 double operator()(double r) const {
1340 double res = pole() + sqrtWidth()*tan(sqrtWidth()*(scale()*r+offset()));
1341 if ( res <= lower() ) return lower()*(1+std::numeric_limits<double>::epsilon());
1342 else if ( res >= upper() ) return upper()*(1-std::numeric_limits<double>::epsilon());
1343 else return res;
1344 }
1345
1346};
1347
1353inline Generator<BreitWigner> breitWigner(double z, double w,
1354 double lower, double upper) {
1355 return Generator<BreitWigner>(z,w,lower,upper);
1356}
1357
1358}
1359
1360}
1361
1362#endif // HERWIG_RandomHelpers_H
double scale() const
Return the scale for random numbers.
double normalization() const
Return the density's normalization.
double theOffset
Offset for random mnumbers.
double lower() const
Return the lower bound of the density generated.
double upper() const
Return the upper bound of the density generated.
double sqrtWidth() const
The square root of width times pole.
double thePole
The position of the pole.
double theSqrtWidth
The square root of width times pole.
double theScale
Scale for random numbers.
Generator(double z, double w, double l, double u)
Construct from pole, width and boundaries.
double offset() const
Return the offset for random mnumbers.
double pole() const
Return the position of the pole.
double operator()(double r) const
Generate the return value according to the implemented density, given a flat random number on the uni...
double value(double x) const
Return the density's value.
virtual double value(double x) const
Return the density's value.
virtual double upper() const
Return the upper bound of the density generated.
virtual double lower() const
Return the lower bound of the density generated.
virtual double operator()(double r) const
Generate the return value according to the implemented density, given a flat random number on the uni...
Generator(const Generator< Density > &gen)
Construct from generator.
virtual double normalization() const
Return the density's normalization.
double value(double x) const
Return the density's value.
double lower() const
Return the lower bound of the density generated.
Generator(double low, double up)
Construct from boundaries.
double normalization() const
Return the density's normalization.
double upper() const
Return the upper bound of the density generated.
double theLower
The lower boundary.
double operator()(double r) const
Generate the return value according to the implemented density, given a flat random number on the uni...
double theUpper
The upper boundary.
double normalization() const
Return the density's normalization.
double lower() const
Return the lower bound of the density generated.
double theOffset
Offset for random mnumbers.
double value(double x) const
Return the density's value.
double upper() const
Return the upper bound of the density generated.
Generator(double z, double l, double u)
Construct from pole and boundaries.
double thePole
The position of the pole.
double operator()(double r) const
Generate the return value according to the implemented density, given a flat random number on the uni...
double pole() const
Return the position of the pole.
double scale() const
Return the scale for random numbers.
double theScale
Scale for random numbers.
double offset() const
Return the offset for random mnumbers.
double theFraction
The fraction of the unit interval considered for the first generator.
double lower() const
Return the lower bound of the density generated.
const Generator< Density2 > & secondGenerator() const
Return the second generator.
Generator< Density2 > theSecondGenerator
The second generator.
const Generator< Density1 > & firstGenerator() const
Return the first generator.
double upper() const
Return the upper bound of the density generated.
double intermediate() const
Return the transition value.
double fraction() const
Return the fraction of the unit interval considered for the first generator.
Generator< Density1 > theFirstGenerator
The first generator.
Generator< Piecewise< Piecewise< Density1, Density2 >, Rescale< Density3 > > > operator,(const matcher< Density3 > &thirdGenerator)
Construct piecewise generators.
double normalization() const
Return the density's normalization.
double value(double x) const
Return the density's value.
double operator()(double r) const
Generate the return value according to the implemented density, given a flat random number on the uni...
Generator< Piecewise< Piecewise< Density1, Density2 >, Density3 > > operator,(const Generator< Density3 > &thirdGenerator)
Construct piecewise generators.
Generator(const Generator< Density1 > &firstGen, const Generator< Density2 > &secondGen)
Construct from generators.
double thePole
The position of the pole.
double normalization() const
Return the density's normalization.
double upper() const
Return the upper bound of the density generated.
double operator()(double r) const
Generate the return value according to the implemented density, given a flat random number on the uni...
double theScale
Scale for random numbers.
double offset() const
Return the offset for random mnumbers.
Generator(double z, double p, double l, double u)
Construct from pole, power and boundaries.
double scale() const
Return the scale for random numbers.
double pole() const
Return the position of the pole.
double lower() const
Return the lower bound of the density generated.
double power() const
Return the power.
double value(double x) const
Return the density's value.
double theOffset
Offset for random mnumbers.
double lower() const
Return the lower bound of the density generated.
double operator()(double r) const
Generate the return value according to the implemented density, given a flat random number on the uni...
const Generator< Density > & generator() const
Return the generator.
Generator< Density > theGenerator
The underlying generator.
Generator(const Generator< Density > &gen, double low, double up)
Construct from generator and new boundaries.
double value(double y) const
Return the density's value.
double normalization() const
Return the density's normalization.
double upper() const
Return the upper bound of the density generated.
double value(double x) const
Return the density's value.
Generator< Density > theGenerator
The underlying generator.
double normalization() const
Return the density's normalization.
double lower() const
Return the lower bound of the density generated.
double operator()(double r) const
Generate the return value according to the implemented density, given a flat random number on the uni...
const Generator< Density > & generator() const
Return the generator.
Generator(const Generator< Density > &gen, double sc)
Construct from generator and scale.
double upper() const
Return the upper bound of the density generated.
double theFraction
The fraction of the unit interval considered for the first generator.
double upper() const
Return the upper bound of the density generated.
Generator< Density1 > theFirstGenerator
The first generator.
Generator< Density2 > theSecondGenerator
The second generator.
const Generator< Density1 > & firstGenerator() const
Return the first generator.
double lower() const
Return the lower bound of the density generated.
double value(double x) const
Return the density's value.
Generator(const Generator< Density1 > &firstGen, const Generator< Density2 > &secondGen)
Construct from generators.
const Generator< Density2 > & secondGenerator() const
Return the second generator.
double normalization() const
Return the density's normalization.
double operator()(double r) const
Generate the return value according to the implemented density, given a flat random number on the uni...
double fraction() const
Return the fraction of the unit interval considered for the first generator.
double lower() const
Return the lower bound of the density generated.
double normalization() const
Return the density's normalization.
double operator()(double r) const
Generate the return value according to the implemented density, given a flat random number on the uni...
double theLower
The lower boundary.
double theUpper
The upper boundary.
Generator(double low, double up)
Construct from boundaries.
double value(double x) const
Return the density's value.
double upper() const
Return the upper bound of the density generated.
Generator< Zero > zero(double low, double up)
Construct a zero density.
Generator< Remap< Density > > operator*(const Generator< Density > &gen, const on &interval)
Construct a remapped density generator.
Generator< BreitWigner > breitWigner(double z, double w, double lower, double upper)
Construct the density 1/((x-z)^2 + abs(w z))
Generator< Inverse > inverse(double z, double lower, double upper)
Construct the density 1/|x-z|.
Generator< Sum< Density1, Density2 > > operator+(const Generator< Density1 > &first, const Generator< Density2 > &second)
Construct the sum of two densities.
Generator< Power > power(double z, double p, double lower, double upper)
Construct the density |(x-z)|^p.
pair< double, double > generate(const Generator< Density > &gen, double r)
Generate a random variable and return its weight.
Generator< Flat > flat(double low, double up)
Construct a constant density.
matcher< Density > match(const Generator< Density > &gen)
Indicate that the argument density should be matched to the previous one in a piecewise definition.
Generator< Piecewise< ToBeDefined, ToBeDefined > > piecewise()
Construct a piecewise defined density.
double sign(double x)
Small helper.
Definition: RandomHelpers.h:30
-*- C++ -*-
constexpr double epsilon
double sqrt(int x)
constexpr double pow(double x, ExponentT p)
constexpr auto sqr(const T &x) -> decltype(x *x)
The density 1/((x-z)^2 + abs(w z))
A constant density.
virtual double value(double x) const =0
Return the density's value.
virtual double operator()(double r) const =0
Generate the return value according to the implemented density, given a flat random number on the uni...
virtual double lower() const =0
Return the lower bound of the density generated.
virtual double normalization() const =0
Return the density's normalization.
virtual double upper() const =0
Return the upper bound of the density generated.
Generator< Piecewise< Density, Rescale< Density2 > > > operator,(const matcher< Density2 > &secondGen)
Construct piecewise generators.
Generator< Piecewise< Density, Density2 > > operator,(const Generator< Density2 > &secondGen)
Construct piecewise generators.
Generator(const Generator< Density > &gen)
Construct from generator.
Generator< Piecewise< Density, ToBeDefined > > operator,(const Generator< Density > &gen)
Construct piecewise generators.
Define the generator concept.
Definition: RandomHelpers.h:40
double operator()(double r) const
Generate the return value according to the implemented density, given a flat random number on the uni...
double normalization() const
Return the density's normalization.
double value(double x) const
Return the density's value.
double upper() const
Return the upper bound of the density generated.
double lower() const
Return the lower bound of the density generated.
A piecewise defined density.
The density |(x-z)|^p.
Remap a density to a new interval.
Add two densities.
Placeholder when constructing piecewise defined densities.
Indicate that the argument density should be matched to the previous one in a piecewise definition.
Generator< Density > generator
The generator to be matched.
matcher(const Generator< Density > &gen)
Construct from generator.
Indicate remapping of a density.
double lower
The new lower boundary.
double upper
The new upper boundary.
on(double a, double b)
Construct from boundaries.