Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-06 09:38:32

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