Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 09:13:42

0001 // -*- C++ -*-
0002 //
0003 // This file is part of YODA -- Yet more Objects for Data Analysis
0004 // Copyright (C) 2008-2024 The YODA collaboration (see AUTHORS for details)
0005 //
0006 #ifndef YODA_Weights_h
0007 #define YODA_Weights_h
0008 
0009 #include "YODA/Exceptions.h"
0010 #include <vector>
0011 #include <string>
0012 #include <map>
0013 #include <ostream>
0014 
0015 namespace YODA {
0016 
0017 
0018   /// @brief A named, vectorised generalisation of an event weight.
0019   ///
0020   /// @todo Accept general Boost.Ranges as constructor args... but start with literal arrays for convenience
0021   /// @todo Autogenerate numerical names if not given
0022   class Weights {
0023   public:
0024 
0025     /// @name Constructors
0026     /// @{
0027 
0028     Weights(const Weights& other)
0029       : _values(other._values)
0030     {  }
0031 
0032     /// Convenience auto-constructor from a single double, since that's the commonest use case.
0033     Weights(double value) {
0034       _values["0"] = value;
0035     }
0036 
0037     /// Constructor from a vector of key/value pairs
0038     Weights(const std::vector<std::pair<std::string, double> >& keys_values) {
0039       for (std::vector<std::pair<std::string, double> >::const_iterator i = keys_values.begin(); i != keys_values.end(); ++i) {
0040         _values[i->first] = i->second;
0041       }
0042     }
0043 
0044     /// Constructor from vectors of keys and values
0045     Weights(const std::vector<std::string>& keys, const std::vector<double>& values) {
0046       if (keys.size() != values.size()) {
0047         throw WeightError("Mismatch in lengths of keys and values vectors in Weights constructor");
0048       }
0049       for (size_t i = 0; i < keys.size(); ++i) {
0050         _values[keys[i]] = values[i];
0051       }
0052     }
0053 
0054     /// Constructor from vectors of keys and a single value, defaulting to 0.0
0055     Weights(const std::vector<std::string>& keys, double value=0.0) {
0056       for (std::vector<std::string>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
0057         _values[*i] = value;
0058       }
0059     }
0060 
0061     /// @}
0062 
0063   public:
0064 
0065 
0066     /// @todo Sorted iterators of pair<std::string, double>
0067 
0068     /// @name Accessors
0069     /// @{
0070 
0071     typedef std::map<std::string, double>::iterator iterator;
0072     typedef std::map<std::string, double>::const_iterator const_iterator;
0073     iterator begin() { return _values.begin(); }
0074     const_iterator begin() const { return _values.begin(); }
0075     iterator end() { return _values.end(); }
0076     const_iterator end() const { return _values.end(); }
0077 
0078     double& operator [] (const std::string& key) {
0079       if (_values.find(key) == _values.end()) {
0080         throw WeightError("No weight found with supplied name");
0081       }
0082       return _values[key];
0083     }
0084     const double& operator [] (const std::string& key) const {
0085       const_iterator rtn = _values.find(key);
0086       if (rtn == _values.end()) {
0087         throw WeightError("No weight found with supplied name");
0088       }
0089       return rtn->second;
0090     }
0091 
0092     double& operator [] (size_t index) {
0093       if (index >= size()) {
0094         throw WeightError("Requested weight index is larger than the weights collection");
0095       }
0096       return _values[keys()[index]];
0097     }
0098     const double& operator [] (size_t index) const {
0099       if (index >= size()) {
0100         throw WeightError("Requested weight index is larger than the weights collection");
0101       }
0102       return _values.find(keys()[index])->second;
0103     }
0104 
0105     /// Number of weights keys
0106     unsigned int size() const {
0107       return _values.size();
0108     }
0109 
0110     /// Sorted list of weight keys
0111     std::vector<std::string> keys() const {
0112       std::vector<std::string> rtn;
0113       rtn.reserve(size());
0114       for (const_iterator i = begin(); i != end(); ++i) {
0115         rtn.push_back(i->first);
0116       }
0117       return rtn;
0118     }
0119 
0120     /// List of weight values, in the order of the sorted keys
0121     std::vector<double> values() const {
0122       std::vector<double> rtn;
0123       rtn.reserve(size());
0124       for (const_iterator i = begin(); i != end(); ++i) {
0125         rtn.push_back(i->second);
0126       }
0127       return rtn;
0128     }
0129 
0130     /// @}
0131 
0132 
0133     /// @name Arithmetic operators as members
0134     /// @{
0135 
0136     /// Add another weights to this
0137     Weights& operator += (const Weights& toAdd) {
0138       if (keys().empty()) _initToMatch(toAdd);
0139       if (keys() != toAdd.keys()) {
0140         throw WeightError("Mismatch in args to Weights += operator");
0141       }
0142       for (size_t i = 0; i < size(); ++i) {
0143         _values[keys()[i]] += toAdd[keys()[i]];
0144       }
0145       return *this;
0146     }
0147 
0148     /// Subtract another weights from this
0149     Weights& operator -= (const Weights& toSubtract) {
0150       if (keys().empty()) _initToMatch(toSubtract);
0151       if (keys() != toSubtract.keys()) {
0152         throw WeightError("Mismatch in args to Weights -= operator");
0153       }
0154       for (size_t i = 0; i < size(); ++i) {
0155         _values[keys()[i]] -= toSubtract[keys()[i]];
0156       }
0157       return *this;
0158     }
0159 
0160     /// Multiply by another weights
0161     Weights& operator *= (const Weights& toMultiplyBy) {
0162       if (keys().empty()) _initToMatch(toMultiplyBy);
0163       if (keys() != toMultiplyBy.keys()) {
0164         throw WeightError("Mismatch in args to Weights *= operator");
0165       }
0166       for (size_t i = 0; i < size(); ++i) {
0167         _values[keys()[i]] *= toMultiplyBy[keys()[i]];
0168       }
0169       return *this;
0170     }
0171 
0172     /// Divide by another weights
0173     Weights& operator /= (const Weights& toDivideBy) {
0174       if (keys().empty()) _initToMatch(toDivideBy);
0175       if (keys() != toDivideBy.keys()) {
0176         throw WeightError("Mismatch in args to Weights /= operator");
0177       }
0178       for (size_t i = 0; i < size(); ++i) {
0179         _values[keys()[i]] /= toDivideBy[keys()[i]];
0180       }
0181       return *this;
0182     }
0183 
0184     /// Multiply by a double
0185     Weights& operator *= (double toMultiplyBy) {
0186       for (size_t i = 0; i < size(); ++i) {
0187         _values[keys()[i]] *= toMultiplyBy;
0188       }
0189       return *this;
0190     }
0191 
0192     /// Divide by a double
0193     Weights& operator /= (double toDivideBy) {
0194       for (size_t i = 0; i < size(); ++i) {
0195         _values[keys()[i]] /= toDivideBy;
0196       }
0197       return *this;
0198     }
0199 
0200     /// Negate
0201     /// @todo Can/should this modify itself and return a reference?
0202     Weights operator - () const {
0203       Weights rtn = *this;
0204       rtn *= -1;
0205       return rtn;
0206     }
0207 
0208     /// @}
0209 
0210 
0211     /// @name Comparison operators
0212     /// @{
0213 
0214     /// Equals
0215     bool operator == (const Weights& other) const {
0216       return this->_values == other._values;
0217     }
0218 
0219     /// Not equals
0220     bool operator != (const Weights& other) const {
0221       return !(*this == other);
0222     }
0223 
0224     /// @}
0225 
0226 
0227     /// @todo Allow implicit casting to double, if single-entried? Or too dangerous and not useful enough?
0228     // double operator (double) () {}
0229 
0230   private:
0231 
0232     /// Initialise an empty list of weights keys to match those of another Weights object
0233     void _initToMatch(const Weights& other) {
0234       if (keys().empty()) {
0235         throw LogicError("Weights::_initToMatch shouldn't ever be called if there are already defined weights keys");
0236       }
0237       for (size_t i = 0; i < other.size(); ++i) {
0238         _values[other.keys()[i]] = 0;
0239       }
0240     }
0241 
0242 
0243   private:
0244 
0245     std::map<std::string, double> _values;
0246 
0247   };
0248 
0249 
0250   /// @name Combining weights: global operators
0251   /// @{
0252 
0253   /// Add two weights
0254   inline Weights operator + (const Weights& first, const Weights& second) {
0255     Weights tmp = first;
0256     tmp += second;
0257     return tmp;
0258   }
0259 
0260   /// Subtract two weights
0261   inline Weights operator - (const Weights& first, const Weights& second) {
0262     Weights tmp = first;
0263     tmp -= second;
0264     return tmp;
0265   }
0266 
0267   /// Multiply two weights
0268   inline Weights operator * (const Weights& first, const Weights& second) {
0269     Weights tmp = first;
0270     tmp *= second;
0271     return tmp;
0272   }
0273 
0274   /// Divide two weights
0275   inline Weights operator / (const Weights& numer, const Weights& denom) {
0276     Weights tmp = numer;
0277     tmp /= denom;
0278     return tmp;
0279   }
0280 
0281 
0282   /// Multiply by a double
0283   inline Weights operator * (double a, const Weights& w) {
0284     Weights tmp = w;
0285     tmp *= a;
0286     return tmp;
0287   }
0288 
0289   /// Multiply by a double
0290   inline Weights operator * (const Weights& w, double a) {
0291     return a * w;
0292   }
0293 
0294   /// Divide by a double
0295   inline Weights operator / (const Weights& w, double a) {
0296     Weights tmp = w;
0297     tmp /= a;
0298     return tmp;
0299   }
0300 
0301   /// Divide a double by a Weights
0302   /// @todo Is this really needed?
0303   inline Weights operator / (double a, const Weights& w) {
0304     Weights tmp(w.keys(), a);
0305     tmp /= w;
0306     return tmp;
0307   }
0308 
0309   /// @}
0310 
0311 
0312   /// Standard text representaion
0313   inline std::ostream& operator<<(std::ostream& out, const Weights& w) {
0314     out << "{ ";
0315     for (Weights::const_iterator i = w.begin(); i != w.end(); ++i) {
0316       if (i != w.begin()) out << ", ";
0317       out << i->first << ": " << i->second;
0318     }
0319     out << "}";
0320     return out;
0321   }
0322 
0323 
0324 }
0325 
0326 #endif