Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-02 08:17:11

0001 /******************************************************************************
0002  * This file is part of libome                                                *
0003  * Copyright (C) 2025 Arnd Behring, Kay Schoenwald                            *
0004  * SPDX-License-Identifier: GPL-3.0-or-later                                  *
0005  ******************************************************************************/
0006 
0007 /**
0008  * \file
0009  * \brief Function wrappers that modify arguments passed to a wrapped callable
0010  */
0011 
0012 #ifndef LIBOME_FUNCTIONS_H
0013 #define LIBOME_FUNCTIONS_H
0014 
0015 #include <type_traits>
0016 #include <functional>
0017 #include <algorithm>
0018 #include <numeric>
0019 #include <limits>
0020 #include <cmath>
0021 #include <cassert>
0022 
0023 namespace apfel
0024 {
0025   namespace ome
0026   {
0027     /// Single parameter identity function
0028     template<typename Tnum>
0029     Tnum f_id(Tnum x) { return(x); }
0030 
0031     /// Single parameter function: 1/2-x
0032     template<typename Tnum>
0033     Tnum f_half(Tnum x) { return(static_cast<Tnum>(1)/static_cast<Tnum>(2) - x); }
0034 
0035     /// Single parameter function: 1-x
0036     template<typename Tnum>
0037     Tnum f_omx(Tnum x) { return(static_cast<Tnum>(1)-x); }
0038 
0039     /// Single parameter function: (a+b*x)
0040     template<typename Tnum, int a, int b>
0041     Tnum f_linear(Tnum x)
0042     {
0043       return(static_cast<Tnum>(a) + static_cast<Tnum>(b)*x);
0044     }
0045 
0046     /// Single parameter function: (a+b*x)/(c+d*x)
0047     template<typename Tnum, int a, int b, int c, int d>
0048     Tnum f_moebius(Tnum x)
0049     {
0050       return((static_cast<Tnum>(a) + static_cast<Tnum>(b)*x) /
0051              (static_cast<Tnum>(c) + static_cast<Tnum>(d)*x));
0052     }
0053 
0054     /**
0055      * \brief Wrapper for callable that shifts the first argument by a fixed value
0056      *
0057      * \details
0058      * Takes a shift and callable at construction and acts as a wrapper which,
0059      * upon evaluation, shifts the first argument by the shift.
0060      *
0061      * \tparam Tnum Numerical type for the shift, the first argument and return
0062      *         type of the evaluation operator.
0063      * \tparam Tfunc Callable type to wrap
0064      * \tparam Trest Type parameter pack for the remainder of the arguments
0065      */
0066     template<typename Tnum, typename Tfunc, typename... Trest>
0067     class func_shift
0068     {
0069     public:
0070       /// Type alias for the numerical type template parameter
0071       using numeric_type = Tnum;
0072       /// Type alias for the callable type template parameter
0073       using element_type = Tfunc;
0074 
0075       /**
0076        * \brief Default constructor
0077        *
0078        * \details
0079        * Calls the default constructor on the target function class and
0080        * initialises shift to zero (i.e. the func_shift class acts as an
0081        * identity).
0082        */
0083       func_shift()
0084         : target_function_(element_type()),
0085           shift_(static_cast<numeric_type>(0)) {};
0086 
0087       /**
0088        * \brief Construct wrapper with given shift and callable
0089        *
0090        * \param shift Value of the shift
0091        * \param target_function Callable object to wrap
0092        */
0093       func_shift(numeric_type shift, element_type target_function)
0094         : target_function_(target_function), shift_(shift) {};
0095 
0096       /**
0097        * \brief Evaluate the wrapped callable with shifted first argument
0098        *
0099        * \param x Argument that gets shifted
0100        * \param rest Function parameter pack that is passed on to the wrapped
0101        *        callable unchanged
0102        *
0103        * \return The value returned by the wrapped callable
0104        */
0105       numeric_type operator()(numeric_type x, Trest... rest) const
0106       {
0107         return(target_function_(x+shift_, rest...));
0108       };
0109 
0110     private:
0111       element_type target_function_;
0112       numeric_type shift_;
0113     };
0114 
0115     /**
0116      * \brief Wrapper for callable that applies a function to the first argument
0117      *
0118      * \details
0119      * Wraps a callable and applies a function to the first argument upon
0120      * evaluation. The callalbe and function are specified at the time of
0121      * construction.
0122      *
0123      * \tparam Tnum Numerical type for the first argument and return type
0124      *         of the evaluation operator
0125      * \tparam Tfunc Callable type to wrap
0126      * \tparam Trest Pack of types for the remaining arguments of the wrapped
0127      *         callable
0128      */
0129     template<typename Tnum, typename Tfunc, typename... Trest>
0130     class func_apply
0131     {
0132     public:
0133       /// Type alias for the numerical type template parameter
0134       using numeric_type = Tnum;
0135       /// Type alias for the callable type template parameter
0136       using element_type = Tfunc;
0137 
0138       /**
0139        * \brief Default constructor
0140        *
0141        * \details
0142        * Calls default constructor on the target function and initialises the
0143        * apply function to f_id<numeric_type> (that is func_apply behaves as
0144        * the identity).
0145        */
0146       func_apply()
0147         : target_function_(element_type()),
0148           apply_function_(f_id<numeric_type>) {};
0149 
0150       /**
0151        * \brief Construct wrapper with given function and callable
0152        *
0153        * \param apply_function Function to apply to the first agument
0154        * \param target_function Callable object to wrap
0155        */
0156       func_apply(std::function<numeric_type(numeric_type)> apply_function,
0157                  element_type target_function)
0158         : target_function_(target_function),
0159           apply_function_(apply_function) {};
0160 
0161       /**
0162        * \brief Evaluate the wrapped callable with the first argument fed
0163        *        through the specified function
0164        *
0165        * \param x Argument that gets modified by the function
0166        * \param rest Function parameter pack that is passed on to the wrapped
0167        *        callable unchanged
0168        *
0169        * \return The value returned by the wrapped callable
0170        */
0171       numeric_type operator()(numeric_type x, Trest... rest) const
0172       {
0173         return(target_function_(apply_function_(x), rest...));
0174       };
0175 
0176     private:
0177       element_type target_function_;
0178       std::function<numeric_type(numeric_type)> apply_function_;
0179     };
0180 
0181     /**
0182      * \brief Wrapper for callable that copies the first argument and applies
0183      *        the logarithm to the first copy
0184      *
0185      * \details
0186      * Wraps a callable that takes one more argument than this wrapper. Upon
0187      * evaluation this wrapper passes the first argument of the wrapper to
0188      * the first two arguments of the wrapped callable. Moreover, it applies
0189      * the logarithm to the first passed argument. I.e. if f wraps g and f is
0190      * called as f(x,...) it calls g(log(x),x,...).
0191      *
0192      * \tparam Tnum Numerical type for the first argument and the return type of
0193      *         the wrapped callable
0194      * \tparam Tfunc Callable type to wrap
0195      * \tparam Trest Pack of types for the remaining arguments of the wrapped
0196      *         callable
0197      */
0198     template<typename Tnum, typename Tfunc, typename... Trest>
0199     class func_copy_and_log
0200     {
0201     public:
0202       /// Type alias for the numerical type template parameter
0203       using numeric_type = Tnum;
0204       /// Type alias for the callable type template parameter
0205       using element_type = Tfunc;
0206 
0207       /**
0208        * \brief Default constructor
0209        *
0210        * \details
0211        * Calls the default constructor on the target function.
0212        */
0213       func_copy_and_log()
0214         : target_function_(element_type()) {};
0215 
0216       /**
0217        * \brief Construct wrapper from callable
0218        *
0219        * \param target_function Callable object to wrap
0220        */
0221       explicit
0222       func_copy_and_log(element_type target_function)
0223         : target_function_(target_function) {};
0224 
0225       /**
0226        * \brief Evaluate the wrapped callable object with the first argument
0227        *        copied and with log() applied to the first copy
0228        *
0229        * \param x Argument to copy
0230        * \param rest Function parameter pack that is passed on to the wrapped
0231        *        callable unchanged
0232        *
0233        * \return The value returned by the wrapped callable
0234        */
0235       numeric_type operator()(numeric_type x, Trest... rest) const
0236       {
0237         using std::log;
0238         return(target_function_(x > static_cast<numeric_type>(0) ? log(x)
0239                                 : std::numeric_limits<numeric_type>::quiet_NaN(), x, rest...));
0240       };
0241 
0242     private:
0243       element_type target_function_;
0244     };
0245 
0246     /**
0247      * \brief Wrapper for callable that emulates \f$1-x\f$ plus function kernels
0248      *
0249      * \details
0250      * Upon evaluation this wrapper takes the first argument \f$x\f$, takes the
0251      * logarithm \f$\log(1-x)\f$ of it and passes it on to the wrapped callable.
0252      * The result from the callable is then divided by \f$1-x\f$. If \f$f\f$
0253      * wraps \f$g\f$, evaluating \f$f\f$ corresponds to
0254      * \f[
0255      *   f(x,\dots) = \frac{g(\log(1-x),\dots)}{1-x}
0256      * \f]
0257      * The idea is that by wrapping a laurent_polynomial with this wrapper, it is
0258      * straightforward to construct a sum of plus function kernels
0259      * \f[
0260      *   p(x,\dots) = \sum_k \frac{\log^k(1-x)}{1-x} c_i(\dots)
0261      * \f]
0262      *
0263      * \tparam Tnum Numerical type for the first argument and the return type of
0264      *         the callable
0265      * \tparam Tfunc Callable type to wrap
0266      * \tparam Trest Pack of types for the remaining arguments of the wrapped
0267      *         callable
0268      */
0269     template<typename Tnum, typename Tfunc, typename... Trest>
0270     class func_plusfunc_omx
0271     {
0272     public:
0273       /// Type alias for the numerical type template parameter
0274       using numeric_type = Tnum;
0275       /// Type alias for the callable type template parameter
0276       using element_type = Tfunc;
0277       /// Boolean type alias indicating that this class has an eval_plus_int method
0278       using has_eval_plus_int = std::true_type;
0279 
0280       /**
0281        * \brief Default constructor
0282        *
0283        * \details
0284        * Calls the default constructor on the target function class.
0285        */
0286       func_plusfunc_omx()
0287         : target_function_(element_type()) {};
0288 
0289       /**
0290        * \brief Construct wrapper from callable
0291        *
0292        * \param target_function Callable object to wrap
0293        */
0294       explicit
0295       func_plusfunc_omx(element_type target_function)
0296         : target_function_(target_function) {};
0297 
0298       /**
0299        * \brief Evaluate the wrapped callable with the first argument x passed
0300        *        through the logarithm and the result divided by x
0301        *
0302        * \param x Argument to be passed through the logarithm before being
0303        *        passed to the wrapped callable
0304        * \param rest Function parameter pack that is passed on to the wrapped
0305        *        callable unchanged
0306        *
0307        * \return The value returned by the wrapped callable, divided by x
0308        */
0309       numeric_type operator()(numeric_type x, Trest... rest) const
0310       {
0311         using std::log;
0312         return(target_function_(log(static_cast<numeric_type>(1)-x), rest...)
0313                / (static_cast<numeric_type>(1)-x));
0314       };
0315 
0316       /**
0317        * \brief Evaluate the integral over the plus function
0318        *
0319        * \details
0320        * For Mellin convolutions, we need an extra term which corresponds to
0321        * \f[
0322        *   I(x) = \int_0^x \mathrm{d}y g(y,\dots)
0323        * \f]
0324        * Since this wrapper is supposed to model \f$1-x\f$ plus function kernels
0325        * and the coeffients \f$c_i(\dots)\f$ do not depend on \f$x\f$, we can
0326        * analytically calculate the integral and just evaluate the result:
0327        * \f[
0328        *   I(x) = \sum_k c_i(\dots) \int_0^x \mathrm{d}y \frac{\log^k(1-y)}{1-y}
0329        *        = \sum_k c_i(\dots) \frac{-\log^{k+1}(1-x)}{k+1}
0330        * \f]
0331        * The implementation is only valid if the wrapped polynomial has no
0332        * negative powers.
0333        *
0334        * \param x Upper integration bound \f$x\f$
0335        * \param rest Function parameter pack that is passed on to the wrapped
0336        *        callable unchanged
0337        *
0338        * \return The value of the integral
0339        */
0340       numeric_type eval_plus_int(numeric_type x, Trest...) const
0341       {
0342         using std::log;
0343         using std::pow;
0344         int min_power = target_function_.min_power();
0345         assert((min_power >= 0, "Only non-negative exponents are supported"));
0346 
0347         numeric_type log_omx = log(static_cast<numeric_type>(1)-x);
0348 
0349         // Calculate the integral over the plus function
0350         size_t num_coeffs = (target_function_.max_power()+1) - min_power;
0351         std::vector<numeric_type> plusfunc_ints(num_coeffs,
0352                                                 static_cast<numeric_type>(0));
0353         // Compute the exponents that appear in the integral over the plus
0354         // functions
0355         std::iota(
0356           plusfunc_ints.begin(),
0357           plusfunc_ints.end(),
0358           static_cast<numeric_type>(min_power+1)
0359         );
0360         // Evaluate the integrals over the plus functions
0361         std::transform(
0362           plusfunc_ints.begin(),
0363           plusfunc_ints.end(),
0364           plusfunc_ints.begin(),
0365         [log_omx](numeric_type e) { return(-pow(log_omx,e)/e); }
0366         );
0367 
0368         // Combine the integrals over the individual plus functions with the
0369         // coefficients
0370         return(target_function_.eval_subst(plusfunc_ints));
0371       };
0372 
0373     private:
0374       element_type target_function_;
0375     };
0376   }
0377 }
0378 
0379 #endif