|
|
|||
File indexing completed on 2026-08-06 09:38:32
0001 // -*- C++ -*- 0002 // 0003 // VSelector.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_VSelector_H 0010 #define ThePEG_VSelector_H 0011 // This is the definition of the ThePEG::VSelector class. 0012 0013 #include "ThePEG/Config/ThePEG.h" 0014 #include <stdexcept> 0015 #include <algorithm> 0016 #include <stdexcept> 0017 0018 namespace ThePEG { 0019 0020 template <typename T, typename WeightType = double> 0021 /** 0022 * VSelector is a templated class for storing objects associated with 0023 * probabilities in a way such that, given a flat random number 0024 * between 0 and 1, an object can be selected according to its 0025 * relative probability. Internally, the objects of class 0026 * <code>T</code> are stored in a vector parallel to a vector of the 0027 * probability of the corresponding object plus the accumulated sum of 0028 * probabilities of all objects before the current one in the 0029 * vector. This allows for fast retreival of an object according to 0030 * its probability. Where fast means that the time increases as a 0031 * logarithm of the number of objects in the selector. 0032 * 0033 * Here is an example on how to use the class:<br> 0034 * <code>double random();</code> // A random generator returning a 0035 * number between 0 and 1.<br> 0036 * <code>class foo;</code> // Any class.<BR> 0037 * <code>VSelector<foo*> bar;</code> // A selector.<BR> 0038 * <code>foo f1, f2;</code> <BR> 0039 * <code>bar.insert(0.5,&f1)</code> // assign probability 0.5<BR> 0040 * <code>bar.insert(0.5,&f2)</code> // to each of f1 and f2<BR> 0041 * <code>foo * f = bar.select(random())</code> // randomly returns 0042 * a pointer to f1 or f2<BR> 0043 * 0044 * @see Selector 0045 */ 0046 class VSelector { 0047 0048 public: 0049 0050 /** A vector of weights. */ 0051 typedef vector<WeightType> WeightVector; 0052 0053 /** The weight vector iterator type. */ 0054 typedef typename WeightVector::const_iterator WIterator; 0055 0056 /** A vector ob objects. */ 0057 typedef vector<T> ObjectVector; 0058 0059 /** The object vector iterator type. */ 0060 typedef typename ObjectVector::iterator iterator; 0061 0062 /** The object vector const iterator type. */ 0063 typedef typename ObjectVector::const_iterator const_iterator; 0064 0065 /** Size type of the underlying vector. */ 0066 typedef typename ObjectVector::size_type size_type; 0067 0068 public: 0069 0070 /** 0071 * Default constructor. 0072 */ 0073 VSelector(size_type reserved = 0) : theSum() 0074 { 0075 reserve(reserved); 0076 } 0077 0078 /** 0079 * Swap the underlying representation with the argument. 0080 */ 0081 void swap(VSelector & s) { 0082 theSums.swap(s.theSums); 0083 theWeights.swap(s.theWeights); 0084 theObjects.swap(s.theObjects); 0085 std::swap(theSum, s.theSum); 0086 } 0087 0088 /** 0089 * Insert an object given a probability for this object. If the 0090 * probability is zero or negative, the object will not be inserted 0091 * and the probability itself is returned. Otherwise the sum of 0092 * probabilities is returned. 0093 */ 0094 WeightType insert(WeightType d, const T & t) { 0095 WeightType newSum = theSum + d; 0096 if ( newSum <= theSum ) return d; 0097 theSums.push_back(theSum = newSum); 0098 theWeights.push_back(d); 0099 theObjects.push_back(t); 0100 return theSum; 0101 } 0102 0103 /** 0104 * Reweight an object previously inserted giving it a new weight. If 0105 * several equivalent objects exists, all of them will be 0106 * reweighted. 0107 */ 0108 WeightType reweight(WeightType, const T &); 0109 0110 /** 0111 * Erase an object, previously inserted. If the object had not been 0112 * inserted, nothing will happen. If several copies of the object 0113 * has been inserted, all will be removed removed. In all cases the 0114 * sum of probabilities is returned. 0115 */ 0116 WeightType erase(const T &); 0117 0118 /** 0119 * Replace all occurencies of told with tnew without changing the 0120 * probability for the entry. 0121 */ 0122 void replace(const T & told, const T & tnew) { 0123 for ( iterator it = theObjects.begin(); it != theObjects.end(); ++it ) 0124 if ( *it == told ) *it = tnew; 0125 } 0126 0127 /** 0128 * Select an object randomly. Given a random number flatly 0129 * distributed in the interval ]0,1[ Select an object according to 0130 * the individual probabilities specified when they were 0131 * inserted. If rnd <= 0 or if rnd >= 1 or the Selector is empty, a 0132 * range_error will be thrown. 0133 * @param rnd a flat random number in the interval ]0,1[ 0134 * @param remainder if non-zero the double pointed to will be set to 0135 * a uniform random number in the interval ]0,1[ calculated from the 0136 * fraction of rnd which was in the range of the selected object. 0137 */ 0138 T & select(double rnd, double * remainder = 0) { 0139 return theObjects[iselect(rnd, remainder)]; 0140 } 0141 0142 /** 0143 * Selct an object randomly. Given a random number flatly 0144 * distributed in the interval ]0,1[ Select an object according to 0145 * the individual probabilities specified when they were 0146 * inserted. If rnd <= 0 or if rnd >= 1 or the Selector is empty, a 0147 * range_error will be thrown. 0148 */ 0149 T & operator[](double rnd) { 0150 return select(rnd, 0); 0151 } 0152 0153 /** 0154 * Selct an object randomly. Given a random number flatly 0155 * distributed in the interval ]0,1[ Select an object according to 0156 * the individual probabilities specified when they were 0157 * inserted. If rnd <= 0 or if rnd >= 1 or the Selector is empty, a 0158 * range_error will be thrown. 0159 * @param rnd a flat random number in the interval ]0,1[ 0160 * @param remainder if non-zero the double pointed to will be set to 0161 * a uniform random number in the interval ]0,1[ calculated from the 0162 * fraction of rnd which was in the range of the selected object. 0163 */ 0164 const T & select(double rnd, double * remainder = 0) const { 0165 return theObjects[iselect(rnd, remainder)]; 0166 } 0167 0168 /** 0169 * Selct an object randomly. Given a random number flatly 0170 * distributed in the interval ]0,1[ select an object according to 0171 * the individual probabilities specified when they were 0172 * inserted. If rnd <= 0 or if rnd >= 1 or the Selector is empty, a 0173 * range_error will be thrown. 0174 */ 0175 const T & operator[](double rnd) const { 0176 return select(rnd, 0); 0177 } 0178 0179 /** 0180 * Selct an object randomly. Given a random number generator which 0181 * generates flat random numbers in the interval ]0,1[ with the 0182 * <code>operator()()</code> function, select an object according to 0183 * the individual probabilities specified when they were 0184 * inserted. If the generated number is outside the allowed range or 0185 * the Selector is empty, a range_error will be thrown. The 0186 * generator should have a push_back function which will be used 0187 * push back a uniform random number in the interval ]0,1[ 0188 * calculated from the fraction of rnd which was in the range of the 0189 * selected object. 0190 */ 0191 template <typename RNDGEN> 0192 T & select(RNDGEN & rnd) { 0193 double rem = 0.0; 0194 T & t = select(rnd(), &rem); 0195 rnd.push_back(rem); 0196 return t; 0197 } 0198 0199 /** 0200 * Selct an object randomly. Given a random number generator which 0201 * generates flat random numbers in the interval ]0,1[ with the 0202 * <code>operator()()</code> function, select an object according to 0203 * the individual probabilities specified when they were 0204 * inserted. If the generated number is outside the allowed range or 0205 * the Selector is empty, a range_error will be thrown. The 0206 * generator should have a push_back function which will be used 0207 * push back a uniform random number in the interval ]0,1[ 0208 * calculated from the fraction of rnd which was in the range of the 0209 * selected object. 0210 */ 0211 template <typename RNDGEN> 0212 const T & select(RNDGEN & rnd) const { 0213 double rem = 0.0; 0214 const T & t = select(rnd(), &rem); 0215 rnd.push_back(rem); 0216 return t; 0217 } 0218 0219 /** 0220 * Return the sum of probabilities of the objects inserted. Note 0221 * that probabilities specified when objects are inserted are 0222 * rescaled with this number to give unit probability for 0223 * 'select()'. 0224 */ 0225 WeightType sum() const { return theSum; } 0226 0227 /** 0228 * Access to the <code>begin()</code> iterator of the underlying 0229 * vector of objects. 0230 */ 0231 const_iterator begin() const { return theObjects.begin(); } 0232 0233 /** 0234 * Access to the <code>end()</code> iterator in the underlying 0235 * vector of objects. 0236 */ 0237 const_iterator end() const { return theObjects.end(); } 0238 0239 /** 0240 * Returns true if the VSelector is empty. 0241 */ 0242 bool empty() const { return theObjects.empty(); } 0243 0244 /** 0245 * Returns the number of objects in the selector. 0246 */ 0247 size_type size() const { return theObjects.size(); } 0248 0249 /** 0250 * Allocate space for a number of objects in the underlying vectors. 0251 */ 0252 void reserve(size_type reserved) { 0253 theSums.reserve(reserved); 0254 theWeights.reserve(reserved); 0255 theObjects.reserve(reserved); 0256 } 0257 0258 /** 0259 * Erases all objects. 0260 */ 0261 void clear() { 0262 theSums.clear(); 0263 theWeights.clear(); 0264 theObjects.clear(); 0265 theSum = WeightType(); 0266 } 0267 0268 /** 0269 * Output to a stream. 0270 */ 0271 template <typename OStream> 0272 void output(OStream &) const; 0273 0274 /** 0275 * Input from a stream. 0276 */ 0277 template <typename IStream> 0278 void input(IStream &); 0279 0280 protected: 0281 0282 /** 0283 * Internal selection engine. 0284 */ 0285 size_type iselect(double rnd, double * remainder) const; 0286 0287 private: 0288 0289 /** 0290 * The vector of accumulated weights for the objects in the selector 0291 */ 0292 WeightVector theSums; 0293 0294 /** 0295 * The vector of weights for the objects in the selector 0296 */ 0297 WeightVector theWeights; 0298 0299 /** 0300 * The vector of objects in the selector. 0301 */ 0302 ObjectVector theObjects; 0303 0304 /** 0305 * The sum of all weights. 0306 */ 0307 WeightType theSum; 0308 0309 }; 0310 0311 /** 0312 * Output a VSelector to a stream. 0313 */ 0314 template <typename OStream, typename T, typename WeightType> 0315 inline OStream & operator<<(OStream & os, 0316 const VSelector<T,WeightType> & s) { 0317 s.output(os); 0318 return os; 0319 } 0320 0321 /** 0322 * Input a VSelector from a stream. 0323 */ 0324 template <typename IStream, typename T, typename WeightType> 0325 inline IStream & operator>>(IStream & is, 0326 VSelector<T,WeightType> & s) { 0327 s.input(is); 0328 return is; 0329 } 0330 0331 0332 } 0333 0334 #include "VSelector.tcc" 0335 0336 #endif /* ThePEG_VSelector_H */
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|