Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-06 09:24:22

0001 // -*- C++ -*-
0002 //
0003 // exponential_generator.icc is part of ExSample -- A Library for Sampling Sudakov-Type Distributions
0004 //
0005 // Copyright (C) 2008-2019 Simon Platzer -- simon.plaetzer@desy.de, The Herwig Collaboration
0006 //
0007 // ExSample is licenced under version 3 of the GPL, see COPYING for details.
0008 // Please respect the MCnet academic guidelines, see GUIDELINES for details.
0009 //
0010 //
0011 namespace exsample {
0012 
0013   template<class Function, class Random>
0014   void exponential_generator<Function,Random>::initialize() {
0015     adaption_info_.dimension = function_->dimension();
0016     adaption_info_.lower_left = function_->support().first;
0017     adaption_info_.upper_right = function_->support().second;
0018     if (adaption_info_.adapt.empty())
0019       adaption_info_.adapt = std::vector<bool>(adaption_info_.dimension,true);
0020     evolution_variable_ = function_->evolution_variable();
0021     evolution_cutoff_ = function_->evolution_cutoff();
0022     sample_variables_ = function_->variable_flags();
0023     sample_other_variables_ = sample_variables_;
0024     sample_other_variables_[evolution_variable_] = false;
0025     last_point_.resize(adaption_info_.dimension);
0026     parametric_selector_ = parametric_selector(&last_point_,sample_other_variables_);
0027     exponent_selector_ = parametric_selector(&last_point_,sample_variables_);
0028     missing_accessor_ = parametric_missing_accessor(&last_parameter_bin_);
0029     parametric_sampler_ = parametric_sampling_selector<rnd_generator<Random> > 
0030       (&last_point_,&last_parameter_bin_,sample_other_variables_,rnd_gen_);
0031     if (initialized_) return;
0032     splits_ = 0;
0033     for ( std::size_t k = 0; k < adaption_info_.dimension; ++k ) {
0034       if ( sample_other_variables_[k] )
0035     continue;
0036       parameter_splits_[k].push_back(adaption_info_.lower_left[k]);
0037       parameter_splits_[k].push_back(adaption_info_.upper_right[k]);
0038     }
0039     root_cell_ = 
0040       binary_tree<cell>(cell(adaption_info_.lower_left,
0041                  adaption_info_.upper_right,
0042                  sample_other_variables_,
0043                  adaption_info_));
0044     root_cell_.value().info().explore(rnd_gen_,adaption_info_,function_);
0045     root_cell_.value().integral(root_cell_.value().info().volume() * root_cell_.value().info().overestimate());
0046     last_exponent_integrand_.resize(1);
0047     check_events_ = adaption_info_.presampling_points;
0048     initialized_ = true;
0049   }
0050 
0051   template<class Function, class Random>
0052   bool exponential_generator<Function,Random>::split () {
0053     if (adaption_info_.freeze_grid <= accepts_)
0054       return false;
0055     if (compensating_)
0056       return false;
0057     if (!(*last_cell_).info().bad(adaption_info_)) return false;
0058     bool dosplit = false;
0059     std::pair<std::size_t,double> sp =
0060       (*last_cell_).info().get_split(adaption_info_,dosplit);
0061     if (!dosplit) return false;
0062     if (!adaption_info_.adapt[sp.first]) return false;
0063     if (splits_ == parameter_hash_bits/2)
0064       return false;
0065     ++splits_;
0066     last_cell_.node().split((*last_cell_).split(sp,rnd_gen_,function_,adaption_info_,
0067                         sample_other_variables_));
0068     if ( !sample_other_variables_[sp.first] ) {
0069       if ( std::find(parameter_splits_[sp.first].begin(),parameter_splits_[sp.first].end(),sp.second)
0070        == parameter_splits_[sp.first].end() ) {
0071     parameter_splits_[sp.first].push_back(sp.second);
0072     std::sort(parameter_splits_[sp.first].begin(),parameter_splits_[sp.first].end());
0073     if ( sp.first == evolution_variable_ ) {
0074       last_exponent_integrand_.push_back(0.);
0075     }
0076       }
0077     }
0078     did_split_ = true;
0079     last_point_ = function_->parameter_point();
0080     root_cell_.tree_accumulate(parametric_selector_,integral_accessor_,std::plus<double>());
0081     exponents_.clear();
0082     get_exponent();
0083     return true;
0084   }
0085 
0086   template<class Function, class Random>
0087   void exponential_generator<Function,Random>::get_exponent () {
0088     last_parameter_bin_.reset();
0089     root_cell_.subtree_hash (exponent_selector_,last_parameter_bin_);
0090     last_exponent_ = exponents_.find(last_parameter_bin_);
0091     if (last_exponent_ != exponents_.end())
0092       return;
0093     exponents_[last_parameter_bin_] = linear_interpolator();
0094     last_exponent_ = exponents_.find(last_parameter_bin_);
0095     double old_evo = last_point_[evolution_variable_];
0096     std::vector<double>::iterator exp_it = last_exponent_integrand_.begin();
0097     for (std::vector<double>::iterator esp = parameter_splits_[evolution_variable_].begin();
0098      esp < std::prev(parameter_splits_[evolution_variable_].end()); ++esp, ++exp_it) {
0099       last_point_[evolution_variable_] = (*esp + *std::next(esp))/2.;
0100       *exp_it = root_cell_.accumulate(parametric_selector_,integral_accessor_,std::plus<double>());
0101     }
0102     exp_it = std::prev(last_exponent_integrand_.end());
0103     double total = 0.;
0104     for (std::vector<double>::iterator esp = std::prev(parameter_splits_[evolution_variable_].end());
0105      esp > parameter_splits_[evolution_variable_].begin(); --esp, --exp_it) {
0106       last_exponent_->second.set_interpolation(*esp,total);
0107       total += (*exp_it) * ((*esp) - (*std::prev(esp)));
0108     }
0109     last_exponent_->second.set_interpolation(parameter_splits_[evolution_variable_].front(),total);
0110     last_point_[evolution_variable_] = old_evo;
0111   }
0112 
0113   template<class Function, class Random>
0114   std::set<std::vector<double> > 
0115   exponential_generator<Function,Random>::parameter_points() {
0116     std::set<std::vector<double> > res;
0117     std::vector<double> pt(adaption_info_.dimension,0.);
0118     recursive_parameter_points(res,pt,0);
0119     return res;
0120   }
0121 
0122   template<class Function, class Random>
0123   void exponential_generator<Function,Random>::
0124   recursive_parameter_points(std::set<std::vector<double> >& res,
0125                  std::vector<double>& pt,
0126                  size_t current) {
0127     if ( current == adaption_info_.dimension ) {
0128       res.insert(pt);
0129       return;
0130     }
0131     if ( sample_variables_[current] ) {
0132       recursive_parameter_points(res,pt,current+1);
0133       return;
0134     }
0135     for ( std::vector<double>::const_iterator sp =
0136         parameter_splits_[current].begin(); 
0137       sp != std::prev(parameter_splits_[current].end()); ++sp ) {
0138       pt[current] = (*sp + *std::next(sp))/2.;
0139       recursive_parameter_points(res,pt,current+1);
0140     }
0141   }
0142 
0143   template<class Function, class Random>
0144   void exponential_generator<Function,Random>::compensate() {
0145     if (!did_split_ || !docompensate_) {
0146       assert(did_split_ || last_cell_ == root_cell_.begin());
0147       exponents_.clear();
0148       last_cell_->info().overestimate(last_value_,last_point_);
0149       last_cell_->integral(last_cell_->info().volume() * last_cell_->info().overestimate());
0150       last_point_ = function_->parameter_point();
0151       get_exponent();
0152       return;
0153     }
0154     std::vector<double> themaxpoint = last_point_;
0155     std::set<std::vector<double> > id_points
0156       = parameter_points();
0157     for ( std::set<std::vector<double> >::const_iterator id =
0158         id_points.begin(); id != id_points.end(); ++id ) {
0159       last_point_ = *id;
0160       get_exponent();
0161     }
0162     std::map<bit_container<parameter_hash_bits>,linear_interpolator >
0163       old_exponents = exponents_;
0164     double old_oe = last_cell_->info().overestimate();
0165     last_cell_->info().overestimate(last_value_,themaxpoint);
0166     last_cell_->integral(last_cell_->info().volume() * last_cell_->info().overestimate());
0167     exponents_.clear();
0168     for ( std::set<std::vector<double> >::const_iterator id =
0169         id_points.begin(); id != id_points.end(); ++id ) {
0170       last_point_ = *id;
0171       get_exponent();
0172       std::map<bit_container<parameter_hash_bits>,linear_interpolator >::iterator
0173     old_exp = old_exponents.find(last_parameter_bin_);
0174       std::map<bit_container<parameter_hash_bits>,linear_interpolator >::iterator
0175     new_exp = exponents_.find(last_parameter_bin_);
0176       assert(old_exp != old_exponents.end() && new_exp != exponents_.end());
0177       double old_norm = 1. - std::exp(-(old_exp->second)(adaption_info_.lower_left[evolution_variable_]));
0178       double new_norm = 1. - std::exp(-(new_exp->second)(adaption_info_.lower_left[evolution_variable_]));
0179       for (binary_tree<cell>::iterator it = root_cell_.begin();
0180        it != root_cell_.end(); ++it) {
0181     if ( !it->info().contains_parameter(last_point_,sample_variables_) )
0182       continue;
0183     double old_int = 0.;
0184     double new_int = 0.;
0185     for ( std::vector<double>::const_iterator sp = parameter_splits_[evolution_variable_].begin();
0186           sp != std::prev(parameter_splits_[evolution_variable_].end()); ++sp ) {
0187       if ( *sp >= it->info().lower_left()[evolution_variable_] &&
0188            *sp < it->info().upper_right()[evolution_variable_] ) {
0189         double xl = *sp;
0190         double xxl = *std::next(sp);
0191         double old_al = 
0192           (old_exp->second.interpolation()[xxl] - old_exp->second.interpolation()[xl]) /
0193           (xxl-xl);
0194         double old_bl = 
0195           (xxl * old_exp->second.interpolation()[xl] - 
0196            xl * old_exp->second.interpolation()[xxl]) /
0197           (xxl-xl);
0198         double new_al = 
0199           (new_exp->second.interpolation()[xxl] - new_exp->second.interpolation()[xl]) /
0200           (xxl-xl);
0201         double new_bl = 
0202           (xxl * new_exp->second.interpolation()[xl] - 
0203            xl * new_exp->second.interpolation()[xxl]) /
0204           (xxl-xl);
0205         if ( std::abs(old_al) > std::numeric_limits<double>::epsilon() ) {
0206           old_int += (exp(-(old_al*xl+old_bl)) - exp(-(old_al*xxl+old_bl)))/old_al;
0207         } else {
0208           old_int += (xxl-xl)*exp(-old_bl);
0209         }
0210         if ( std::abs(new_al) > std::numeric_limits<double>::epsilon() ) {
0211           new_int += (exp(-(new_al*xl+new_bl)) - exp(-(new_al*xxl+new_bl)))/new_al;
0212         } else {
0213           new_int += (xxl-xl)*exp(-new_bl);
0214         }
0215       }
0216     }
0217     double scaling;
0218     if (it != last_cell_) {
0219       if (old_int > std::numeric_limits<double>::epsilon() &&
0220           new_int > std::numeric_limits<double>::epsilon())
0221         scaling = ((old_norm * new_int) /
0222                (new_norm * old_int)) - 1.;
0223       else
0224         scaling = 0.;
0225     } else {
0226       if (old_int > std::numeric_limits<double>::epsilon() &&
0227           new_int > std::numeric_limits<double>::epsilon())
0228         scaling = ((last_value_ * old_norm * new_int) /
0229                (old_oe * new_norm * old_int)) - 1.;
0230       else
0231         scaling = 0.;
0232     }
0233     it->info().parametric_missing(last_parameter_bin_,
0234                       it->info().parametric_missing(last_parameter_bin_) +
0235                       static_cast<int>(round(scaling * it->info().attempted())));
0236     if (it->info().parametric_missing(last_parameter_bin_) != 0) {
0237       compensating_ = true;
0238     }
0239       }
0240     }
0241     last_point_ = function_->parameter_point();
0242   }
0243 
0244   template<class Function, class Random>
0245   double exponential_generator<Function,Random>::generate(double enhance) {
0246     if ( enhance == 0.0 )
0247       return 0.;
0248     if (compensating_) {
0249       compensating_ = false;
0250       for (binary_tree<cell>::iterator it = root_cell_.begin();
0251        it != root_cell_.end(); ++it)
0252     if (it->info().parametric_compensating()) {
0253       compensating_ = true;
0254       break;
0255     }
0256       parametric_sampler_.compensate(compensating_);
0257     }
0258     last_point_ = function_->parameter_point();
0259     if (last_point_[evolution_variable_] < evolution_cutoff_) {
0260       return 0.;
0261     }
0262     unsigned long n_hit_miss = 0;
0263     unsigned long n_select = 0;
0264     double minus_log_r;
0265     root_cell_.tree_accumulate(parametric_selector_,integral_accessor_,std::plus<double>());
0266     get_exponent();
0267     while (true) {
0268       n_select = 0;
0269       minus_log_r = -std::log(rnd_gen_())/enhance/detuning_ +
0270     last_exponent_->second(last_point_[evolution_variable_]);
0271       if (!last_exponent_->second.invertible(minus_log_r)) {
0272     return 0.;
0273       }
0274       try {
0275     last_point_[evolution_variable_] = last_exponent_->second.unique_inverse(minus_log_r);
0276       } catch (constant_interpolation& c) {
0277     last_point_[evolution_variable_] = rnd_gen_(c.range.first,c.range.second);
0278       }
0279       assert(std::isfinite(last_point_[evolution_variable_]));
0280       if (last_point_[evolution_variable_] < evolution_cutoff_) {
0281     return 0.;
0282       }
0283       ++attempts_;
0284       if (compensating_) {
0285     root_cell_.tree_accumulate(missing_accessor_,std::plus<int>());
0286       }
0287       if (parameter_splits_[evolution_variable_].size() > 2)
0288     root_cell_.tree_accumulate(parametric_selector_,integral_accessor_,std::plus<double>());
0289       if (did_split_)
0290     while ((last_cell_ = root_cell_.select(parametric_sampler_)) == root_cell_.end()) {
0291       root_cell_.tree_accumulate(missing_accessor_,std::plus<int>());
0292       if(++n_select > adaption_info_.maxtry)
0293         throw selection_maxtry();
0294     }
0295       else
0296     last_cell_ = root_cell_.begin();
0297       last_cell_->info().select(rnd_gen_,last_point_,sample_other_variables_);
0298       last_value_ = function_->evaluate(last_point_);
0299       assert(last_value_ >= 0.);
0300       last_cell_->info().selected(last_point_,last_value_,adaption_info_);
0301       if (last_value_ > last_cell_->info().overestimate()) {
0302     if ( std::abs(last_value_)/last_cell_->info().overestimate() > 2. ) {
0303       last_value_ = 
0304         last_cell_->info().overestimate()*
0305         (1.+exp(2.*(2.-std::abs(last_value_)/last_cell_->info().overestimate())));
0306     }
0307     compensate();
0308     throw exponential_regenerate();
0309       } 
0310       if (last_cell_->info().attempted() % check_events_ == 0) {
0311     if (split()) {
0312       throw exponential_regenerate();
0313     }
0314       }
0315       if (last_value_/last_cell_->info().overestimate()/detuning_ > rnd_gen_()) {
0316     function_->accept(last_point_,enhance*last_value_,enhance*detuning_*last_cell_->info().overestimate());
0317     break;
0318       }
0319       if ( last_value_ != 0.0 ) {
0320     function_->veto(last_point_,enhance*last_value_,enhance*detuning_*last_cell_->info().overestimate());
0321       }
0322       if(++n_hit_miss > adaption_info_.maxtry)
0323     throw hit_and_miss_maxtry();
0324     }
0325     if (last_value_ == 0.)
0326       return 0.;
0327     ++accepts_;
0328     ++check_events_;
0329     last_cell_->info().accept();
0330     return 1.;
0331   }
0332 
0333 
0334   template<class Function, class Random>
0335   template<class OStream>
0336   void exponential_generator<Function,Random>::put (OStream& os) const {
0337     os << check_events_; ostream_traits<OStream>::separator(os);
0338     adaption_info_.put(os);
0339     root_cell_.put(os);
0340     os << did_split_; ostream_traits<OStream>::separator(os);
0341     os << initialized_; ostream_traits<OStream>::separator(os);
0342     os << evolution_variable_; ostream_traits<OStream>::separator(os);
0343     os << evolution_cutoff_; ostream_traits<OStream>::separator(os);
0344     os << sample_variables_; ostream_traits<OStream>::separator(os);
0345     os << sample_other_variables_; ostream_traits<OStream>::separator(os);
0346     os << parameter_splits_; ostream_traits<OStream>::separator(os);
0347     // last_cell_ is selected new so we ignore it here
0348     os << last_point_; ostream_traits<OStream>::separator(os);
0349     os << last_value_; ostream_traits<OStream>::separator(os);
0350     last_parameter_bin_.put(os);
0351     os << exponents_.size(); ostream_traits<OStream>::separator(os);
0352     for ( std::map<bit_container<parameter_hash_bits>,linear_interpolator >::const_iterator
0353         ex = exponents_.begin(); ex != exponents_.end() ; ++ex ) {
0354       ex->first.put(os);
0355       ex->second.put(os);
0356     }
0357     os << last_exponent_integrand_; ostream_traits<OStream>::separator(os);
0358     os << compensating_; ostream_traits<OStream>::separator(os);
0359     os << attempts_; ostream_traits<OStream>::separator(os);
0360     os << accepts_; ostream_traits<OStream>::separator(os);
0361     os << splits_; ostream_traits<OStream>::separator(os);
0362     os << docompensate_; ostream_traits<OStream>::separator(os);
0363   }
0364 
0365   template<class Function, class Random>
0366   template<class IStream>
0367   void exponential_generator<Function,Random>::get (IStream& is) {
0368     is >> check_events_;
0369     adaption_info_.get(is);
0370     root_cell_.get(is);
0371     is >> did_split_ >> initialized_ >> evolution_variable_
0372        >> evolution_cutoff_ >> sample_variables_ >> sample_other_variables_
0373        >> parameter_splits_;
0374     // last_cell_ is selected new so we ignore it here
0375     is >> last_point_ >> last_value_;
0376     last_parameter_bin_.get(is);
0377     size_t dim; is >> dim;
0378     for ( size_t k = 0; k < dim ; ++k ) {
0379       bit_container<parameter_hash_bits> key;
0380       key.get(is);
0381       exponents_[key].get(is);
0382     }
0383     is >> last_exponent_integrand_;
0384     last_exponent_ = exponents_.find(last_parameter_bin_);
0385     is >> compensating_ >> attempts_ >> accepts_ >> splits_ >> docompensate_;
0386   }
0387 
0388 }