Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-13 10:32:15

0001 // -*- C++ -*-
0002 //
0003 // This file is part of YODA -- Yet more Objects for Data Analysis
0004 // Copyright (C) 2008-2025 The YODA collaboration (see AUTHORS for details)
0005 //
0006 #ifndef YODA_TRANSFORMATION_H
0007 #define YODA_TRANSFORMATION_H
0008 
0009 #include "YODA/Exceptions.h"
0010 #include "YODA/Utils/MathUtils.h"
0011 #include "YODA/Utils/ndarray.h"
0012 #include <algorithm>
0013 #include <functional>
0014 #include <map>
0015 #include <utility>
0016 
0017 
0018 namespace YODA {
0019 
0020 
0021   /// Generalised transformation
0022   ///
0023   /// The tranformation uses a functor that
0024   /// acts on a double (possibly with additional
0025   /// arguments) and returns a double.
0026   /// The generalisation is in the number of
0027   /// dimensions in which the trf can be applied.
0028   template<size_t N, typename... Args>
0029   class Transformation {
0030   public:
0031 
0032     /// Convenient aliases
0033     using Pair = std::pair<double,double>;
0034     using NdVal = typename Utils::ndarray<double, N>;
0035     using NdValPair = typename Utils::ndarray<Pair, N>;
0036     using Breakdown = std::map<std::string,std::pair<double,double>>;
0037 
0038 
0039     /// @name Constructors
0040     /// @{
0041 
0042     /// No nullary constructor since a trf method
0043     /// should always be supplied
0044     Transformation() = delete;
0045 
0046     /// @brief Default constructor setting the trf method
0047     Transformation(const std::function<double(double, Args...)>& fn) : _Fn(fn) { }
0048 
0049     /// @brief Default constructor setting the trf method
0050     Transformation(std::function<double(double, Args...)>&& fn) : _Fn(std::move(fn)) { }
0051 
0052 
0053     /// @brief Operator calling the functor
0054     double operator()(const double v, Args&&... args) const { return _Fn(v, std::forward<Args>(args)...); }
0055 
0056     /// @}
0057 
0058 
0059     /// @name Modifiers
0060     /// @{
0061 
0062     /// @brief Transform value @a val
0063     void transform(double& val, Args&&... args) const { val = _Fn(val, std::forward<Args>(args)...); }
0064 
0065     /// @brief Transform values @a vals
0066     void transform(NdVal& vals, Args&&... args) const {
0067       for (double& val : vals) {
0068         transform(val, std::forward<Args>(args)...);
0069       }
0070     }
0071 
0072     // @todo allow arbitrary arrays, not just NdVal ...
0073 
0074     /// @brief Transform value @a val and breakdown of signed error pairs @a signed_errs
0075     void transform(double& val, Breakdown& signed_errs, Args&&... args) const {
0076       // keep track of original central value
0077       const double oldval = val;
0078       // transform central value
0079       transform(val, std::forward<Args>(args)...);
0080       // transform errors
0081       for (auto& item : signed_errs) {
0082         item.second.first = _Fn(oldval + item.second.first, std::forward<Args>(args)...) - val;
0083         item.second.second = _Fn(oldval + item.second.second, std::forward<Args>(args)...) - val;
0084       }
0085     }
0086 
0087     /// @brief Transform value @a val and error pair @a errs
0088     void transform(double& val, Pair& errs, Args&&... args) const {
0089       // transform errors
0090       const double trf_min = _Fn(val - errs.first, std::forward<Args>(args)...);
0091       const double trf_max = _Fn(val + errs.second, std::forward<Args>(args)...);
0092       // transform central value
0093       transform(val, std::forward<Args>(args)...);
0094       // Deal with possible inversions of min/max ordering under the transformation
0095       const double new_min = std::min(trf_min, trf_max);
0096       const double new_max = std::max(trf_min, trf_max);
0097       errs = std::make_pair(val - new_min, new_max - val);
0098     }
0099 
0100     /// @brief Transform values @a vals and error pairs @a errs
0101     void transform(NdVal& vals, NdValPair& errs, Args&&... args) const {
0102       for (size_t i = 0; i < N; ++i) {
0103         transform(vals[i], errs[i], std::forward<Args>(args)...);
0104       }
0105     }
0106 
0107     /// @}
0108 
0109   protected:
0110 
0111     /// @name Functor
0112     /// @{
0113 
0114     std::function<double(double, Args...)> _Fn;
0115 
0116     /// @}
0117 
0118   };
0119 
0120 
0121 
0122   /// @name Convenient aliases
0123   /// @{
0124 
0125   template<size_t N>
0126   using Trf = Transformation<N>;
0127 
0128   /// @}
0129 
0130 }
0131 
0132 #endif