|
|
|||
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
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|