|
|
|||
File indexing completed on 2026-08-06 09:38:31
0001 // -*- C++ -*- 0002 // 0003 // CompSelector.h is a part of ThePEG - Toolkit for HEP Event Generation 0004 // Copyright (C) 1999-2019 Leif Lonnblad 0005 // 0006 // ThePEG is licenced under version 3 of the GPL, see COPYING for details. 0007 // Please respect the MCnet academic guidelines, see GUIDELINES for details. 0008 // 0009 #ifndef THEPEG_CompSelector_H 0010 #define THEPEG_CompSelector_H 0011 // 0012 // This is the declaration of the CompSelector class. 0013 // 0014 0015 #include "ThePEG/Utilities/Selector.h" 0016 0017 namespace ThePEG { 0018 0019 /** 0020 * The CompSelector class works like the Selector class in that it can 0021 * be used to randomly select objects according to associated 0022 * probabilities. In addition, the CompSelector class is able to 0023 * handle the case where the associated probabilities are 0024 * overestimates and the selected object will be discarded according 0025 * to some weight. If then a weight above one is encountered, this 0026 * means that the overestimated probability for the selected object 0027 * was wrong and it should in fact have been higher. If this happens, 0028 * the CompSelecteor will go into compensation mode, which means that 0029 * the selected object will be oversampled a period after the 0030 * violation to compensate for having been undersampled before. Also 0031 * the associated probability is adjusted to reflect the new 0032 * overestimate. 0033 * 0034 * The available functions are not as many as in Selector, and some of 0035 * the works somewhat differently. Before starting sampling the 0036 * objects should be added to a CompSelector object with the insert() 0037 * function. To selct an object the select() function should be 0038 * used. After that the weight with which the object should be 0039 * accepted should be presented with the reweight() function which 0040 * normally returns zero. If, however, the weight is larger than unity 0041 * the new overestimated probability is returned and the CompSelector 0042 * enters the compensating mode. Note that the weight is passed as a 0043 * reference and may be changed in by the reweight function if in the 0044 * compensating mode. 0045 */ 0046 template <typename T, typename WeightType = double> 0047 class CompSelector { 0048 0049 public: 0050 0051 /** @name Standard constructors and destructors. */ 0052 //@{ 0053 /** 0054 * The default constructor. The optional argument gives the margin 0055 * used to get a new overestimated probability for an object when 0056 * entering compensation mode. 0057 */ 0058 CompSelector(double newMargin = 1.1, double newTolerance = 1.0e-6) 0059 : N(0), last(), theMargin(newMargin), theTolerance(newTolerance) {} 0060 //@} 0061 0062 public: 0063 0064 /** @name The main function controlling the selection and compensation. */ 0065 //@{ 0066 /** 0067 * Insert an object given a probability for this object. If the 0068 * probability is zero or negative, the object will not be inserted 0069 * and the probability itself is returned. Otherwise the sum of 0070 * probabilities so far is returned. Note that if selection has 0071 * already started and this CompSelector is in compensating mode, it 0072 * will immediately leave this mode and the selection procedure will 0073 * start from scratch. 0074 */ 0075 WeightType insert(WeightType d, const T & t) { 0076 reset(); 0077 return selector.insert(d, t); 0078 } 0079 0080 /** 0081 * Selct an object randomly. Given a random number generator which 0082 * generates flat random numbers in the interval ]0,1[ with the 0083 * <code>operator()()</code> function, select an object according to 0084 * the individual probabilities specified when they were 0085 * inserted. If the generated number is outside the allowed range or 0086 * the Selector is empty, a range_error will be thrown. The 0087 * generator should have a push_back function which will be used 0088 * push back a uniform random number in the interval ]0,1[ 0089 * calculated from the fraction of rnd which was in the range of the 0090 * selected object. 0091 */ 0092 template <typename RNDGEN> 0093 T & select(RNDGEN & rnd) { 0094 ++N; 0095 if ( !compensating() ) last = selector.select(rnd); 0096 return last; 0097 } 0098 0099 /** 0100 * Report the weight associated with the last selected 0101 * object. Returns the zero if weight was below unity, otherwise the 0102 * compensation mode will be entered and the new overestimated 0103 * probabilty for the last selected object will be returned. 0104 */ 0105 WeightType reweight(double & weight) { 0106 if ( abs(weight) > 1.0 + tolerance() ) { 0107 // Retrieve the old overestimate of the object by seing how much 0108 // the summed weights are decreased when removing the object. 0109 WeightType oldtot = selector.sum(); 0110 WeightType oldmax = oldtot - selector.erase(last); 0111 WeightType newmax = oldmax*abs(weight)*margin(); 0112 WeightType newtot = selector.insert(newmax, last); 0113 double rat = newmax/oldmax; 0114 0115 // Setup the new compensation level. 0116 Level level; 0117 level.weight = 1.0/rat; 0118 level.lastN = long(N*newtot/oldtot); 0119 0120 // If we are already compensating, reweight the previous 0121 // compensation levels. 0122 for ( int i = 0, M = levels.size(); i < M; ++i ) { 0123 levels[i].lastN = long(levels[i].lastN*newtot/oldtot); 0124 levels[i].weight /= rat; 0125 } 0126 levels.push_back(level); 0127 weight /= rat; 0128 return newmax; 0129 } 0130 0131 // If we are compensating we should only accept the selection if the 0132 // weight is above the previous overestimate. 0133 if ( compensating() ) if ( abs(weight) < levels.back().weight ) weight = 0.0; 0134 0135 return WeightType(); 0136 } 0137 0138 /** 0139 * Exit compensation mode and start selection procedure from 0140 * scratch. 0141 */ 0142 void reset() { 0143 N = 0; 0144 levels.clear(); 0145 last = T(); 0146 } 0147 0148 /** 0149 * Erases all objects. 0150 */ 0151 void clear() { 0152 selector.clear(); 0153 reset(); 0154 } 0155 0156 /** 0157 * Set the margin used to get a new overestimated probability for an 0158 * object when entering compensation mode. 0159 */ 0160 void margin(double m) { theMargin = m; } 0161 0162 /** 0163 * Set the tolerance for how much a weight is allowed to be 0164 * larger than unity before starting the compensation. 0165 */ 0166 void tolerance(double t) { theTolerance = t; } 0167 //@} 0168 0169 0170 /** @name Simple access functions. */ 0171 //@{ 0172 /** 0173 * Return true if this CompSelector is in a compensating state. 0174 */ 0175 bool compensating() { 0176 // Leave all levels which has reached there 'expiry date'. 0177 while ( levels.size() && levels.back().lastN < N ) levels.pop_back(); 0178 return !levels.empty(); 0179 } 0180 0181 /** 0182 * If in a compensating mode, return the number of selection needed 0183 * before exiting this mode. 0184 */ 0185 long compleft() const { return levels.empty()? 0: levels.back().lastN - N; } 0186 0187 /** 0188 * Return the sum of probabilities of the objects inserted. Note 0189 * that probabilities specified when objects are inserted are 0190 * rescaled with this number to give unit probability for 0191 * 'select()'. 0192 */ 0193 WeightType sum() const { return selector.sum(); } 0194 0195 /** 0196 * Return the margin used to get a new overestimated probability for an 0197 * object when entering compensation mode. 0198 */ 0199 double margin() const { return theMargin; } 0200 0201 /** 0202 * Return the tolerance for how much a weight is allowed to be 0203 * larger than unity before starting the compensation. 0204 */ 0205 double tolerance() const { return theTolerance; } 0206 //@} 0207 0208 /** @name I/O functions. */ 0209 //@{ 0210 /** 0211 * Output to a stream. 0212 */ 0213 template <typename OStream> 0214 void output(OStream & os) const { 0215 os << selector << N << last << theMargin << theTolerance << levels.size(); 0216 for ( int i = 0, M = levels.size(); i < M; ++i ) 0217 os << levels[i].lastN << levels[i].weight; 0218 } 0219 0220 /** 0221 * Input from a stream. 0222 */ 0223 template <typename IStream> 0224 void input(IStream & is) { 0225 long M; 0226 is >> selector >> N >> last >> theMargin >> theTolerance >> M; 0227 levels.resize(M); 0228 for ( int i = 0; i < M; ++i ) is >> levels[i].lastN >> levels[i].weight; 0229 } 0230 //@} 0231 0232 private: 0233 0234 /** 0235 * Internal struct used for bookkeeping when compensating. 0236 */ 0237 struct Level { 0238 0239 /** 0240 * The selection number at which point this level of compensation 0241 * is ended. 0242 */ 0243 long lastN; 0244 0245 /** 0246 * The minimum weight allowed when compensating on this level. 0247 */ 0248 double weight; 0249 0250 }; 0251 0252 private: 0253 0254 /** 0255 * The underlying selector 0256 */ 0257 Selector<T,WeightType> selector; 0258 0259 /** 0260 * The number of selections so far. 0261 */ 0262 long N; 0263 0264 /** 0265 * The last selected object. 0266 */ 0267 T last; 0268 0269 /** 0270 * The margin used to get a new overestimated probability for an 0271 * object when entering compensation mode. 0272 */ 0273 double theMargin; 0274 0275 /** 0276 * Set the tolerance for how much a weight is allowed to be 0277 * larger than unity before starting the compensation. 0278 */ 0279 double theTolerance; 0280 0281 /** 0282 * The currently active compensation levels. 0283 */ 0284 vector<Level> levels; 0285 0286 }; 0287 0288 /** 0289 * Output a Selector to a stream. 0290 */ 0291 template <typename OStream, typename T, typename WeightType> 0292 inline OStream & operator<<(OStream & os, 0293 const CompSelector<T,WeightType> & s) { 0294 s.output(os); 0295 return os; 0296 } 0297 0298 /** 0299 * Input a Selector from a stream. 0300 */ 0301 template <typename IStream, typename T, typename WeightType> 0302 inline IStream & operator>>(IStream & is, 0303 CompSelector<T,WeightType> & s) { 0304 s.input(is); 0305 return is; 0306 } 0307 0308 } 0309 0310 #endif /* THEPEG_CompSelector_H */
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|