Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-06-11 02:59:55

0001 #ifndef DataFormats_L1TrackTrigger_TTBV_h
0002 #define DataFormats_L1TrackTrigger_TTBV_h
0003 
0004 #include "FWCore/Utilities/interface/Exception.h"
0005 
0006 #include <bitset>
0007 #include <array>
0008 #include <string>
0009 #include <algorithm>
0010 #include <cmath>
0011 #include <utility>
0012 #include <vector>
0013 #include <iostream>
0014 
0015 /*! 
0016  * \class  TTBV
0017  * \brief  Bit vector used by Track Trigger emulators. Mainly used to convert
0018  *         integers into arbitrary (within margin) sized two's complement strings.
0019  * \author Thomas Schuh
0020  * \date   2020, Jan
0021  */
0022 class TTBV {
0023 public:
0024   static constexpr int S_ = 64;  // Frame width of emp infrastructure f/w, max number of bits a TTBV can handle
0025 private:
0026   bool twos_;           // Two's complement (true) or binary (false)
0027   int size_;            // number or bits
0028   std::bitset<S_> bs_;  // underlying storage
0029 public:
0030   // constructor: default
0031   TTBV() : twos_(false), size_(0), bs_() {}
0032   // constructor: double precision (IEEE 754); from most to least significant bit: 1 bit sign + 11 bit binary exponent + 52 bit binary mantisse
0033   TTBV(const double d) : twos_(false), size_(S_) {
0034     int index(0);
0035     const char* c = reinterpret_cast<const char*>(&d);
0036     for (int iByte = 0; iByte < (int)sizeof(d); iByte++) {
0037       const std::bitset<std::numeric_limits<unsigned char>::digits> byte(*(c + iByte));
0038       for (int bit = 0; bit < std::numeric_limits<unsigned char>::digits; bit++)
0039         bs_[index++] = byte[bit];
0040     }
0041   }
0042 
0043   // constructor: unsigned int value
0044   TTBV(unsigned long long int value, int size) : twos_(false), size_(size), bs_(value) { checkU(value); }
0045 
0046   // constructor: int value
0047   TTBV(int value, int size, bool twos = false)
0048       : twos_(twos), size_(size), bs_((!twos || value >= 0) ? value : value + iMax()) {
0049     checkI(value);
0050   }
0051 
0052   // constructor: double value + precision, biased (floor) representation
0053   TTBV(double value, double base, int size, bool twos = false)
0054       : TTBV((int)std::floor(value / base + 1.e-12), size, twos) {}
0055 
0056   // constructor: string
0057   TTBV(const std::string& str, bool twos = false) : twos_(twos), size_(str.size()), bs_(str) {}
0058 
0059   // constructor: bitset
0060   TTBV(const std::bitset<S_>& bs, bool twos = false) : twos_(twos), size_(S_), bs_(bs) {}
0061 
0062   // constructor: slice reinterpret sign
0063   TTBV(const TTBV& ttBV, int begin, int end = 0, bool twos = false) : twos_(twos), size_(begin - end), bs_(ttBV.bs_) {
0064     bs_ <<= S_ - begin;
0065     bs_ >>= S_ - begin + end;
0066   }
0067 
0068   // Two's complement (true) or binary (false)
0069   bool twos() const { return twos_; }
0070   // number or bits
0071   int size() const { return size_; }
0072   // underlying storage
0073   const std::bitset<S_>& bs() const { return bs_; }
0074 
0075   // access: single bit value
0076   bool operator[](int pos) const { return bs_[pos]; }
0077 
0078   // access: single bit reference
0079   std::bitset<S_>::reference operator[](int pos) { return bs_[pos]; }
0080 
0081   // access: single bit value with bounds check
0082   bool test(int pos) const { return bs_.test(pos); }
0083 
0084   // access: most significant bit copy
0085   bool msb() const { return bs_[size_ - 1]; }
0086 
0087   // access: most significant bit reference
0088   std::bitset<S_>::reference msb() { return bs_[size_ - 1]; }
0089 
0090   // access: members of underlying bitset
0091 
0092   bool all() const { return bs_.all(); }
0093   bool any() const { return bs_.any(); }
0094   bool none() const { return bs_.none(); }
0095   int count() const { return bs_.count(); }
0096 
0097   // operator: comparisons equal
0098   bool operator==(const TTBV& rhs) const { return bs_ == rhs.bs_; }
0099 
0100   // operator: comparisons not equal
0101   bool operator!=(const TTBV& rhs) const { return bs_ != rhs.bs_; }
0102 
0103   // operator: boolean and
0104   TTBV& operator&=(const TTBV& rhs) {
0105     bs_ &= rhs.bs_;
0106     return *this;
0107   }
0108 
0109   // operator: boolean and
0110   TTBV operator&&(const TTBV& rhs) {
0111     TTBV copy(*this);
0112     return copy &= rhs;
0113   }
0114 
0115   // operator: boolean or
0116   TTBV& operator|=(const TTBV& rhs) {
0117     bs_ |= rhs.bs_;
0118     return *this;
0119   }
0120 
0121   // operator: boolean or
0122   TTBV operator||(const TTBV& rhs) {
0123     TTBV copy(*this);
0124     return copy |= rhs;
0125   }
0126 
0127   // operator: boolean xor
0128   TTBV& operator^=(const TTBV& rhs) {
0129     bs_ ^= rhs.bs_;
0130     return *this;
0131   }
0132 
0133   // operator: not
0134   TTBV operator~() const {
0135     TTBV bv(*this);
0136     return bv.flip();
0137   }
0138 
0139   // reference operator: bit remove right
0140   TTBV& operator>>=(int pos) {
0141     bs_ >>= pos;
0142     size_ -= pos;
0143     return *this;
0144   }
0145 
0146   // reference operator: bit remove left
0147   TTBV& operator<<=(int pos) {
0148     bs_ <<= S_ - size_ + pos;
0149     bs_ >>= S_ - size_ + pos;
0150     size_ -= pos;
0151     return *this;
0152   }
0153 
0154   // operator: bit remove left copy
0155   TTBV operator<<(int pos) const {
0156     TTBV bv(*this);
0157     return bv <<= pos;
0158   }
0159 
0160   // operator: bit remove right copy
0161   TTBV operator>>(int pos) const {
0162     TTBV bv(*this);
0163     return bv >>= pos;
0164   }
0165 
0166   // reference operator: concatenation
0167   TTBV& operator+=(const TTBV& rhs) {
0168     bs_ <<= rhs.size();
0169     bs_ |= rhs.bs_;
0170     size_ += rhs.size();
0171     return *this;
0172   }
0173 
0174   // operator: concatenation copy
0175   TTBV operator+(const TTBV& rhs) const {
0176     TTBV lhs(*this);
0177     return lhs += rhs;
0178   }
0179 
0180   // operator: value increment, overflow protected
0181   TTBV& operator++() {
0182     bs_ = std::bitset<S_>(bs_.to_ullong() + 1);
0183     this->resize(size_);
0184     return *this;
0185   }
0186 
0187   // manipulation: all bits set to 0
0188   TTBV& reset() {
0189     bs_.reset();
0190     return *this;
0191   }
0192 
0193   // manipulation: all bits set to 1
0194   TTBV& set() {
0195     for (int n = 0; n < size_; n++)
0196       bs_.set(n);
0197     return *this;
0198   }
0199 
0200   // manipulation: all bits flip 1 to 0 and vice versa
0201   TTBV& flip() {
0202     for (int n = 0; n < size_; n++)
0203       bs_.flip(n);
0204     return *this;
0205   }
0206 
0207   // manipulation: single bit set to 0
0208   TTBV& reset(int pos) {
0209     bs_.reset(pos);
0210     return *this;
0211   }
0212 
0213   // manipulation: single bit set to 1
0214   TTBV& set(int pos) {
0215     bs_.set(pos);
0216     return *this;
0217   }
0218 
0219   // manipulation: multiple bit set to 1
0220   TTBV& set(std::vector<int> vpos) {
0221     for (int pos : vpos)
0222       bs_.set(pos);
0223     return *this;
0224   }
0225 
0226   // manipulation: single bit flip 1 to 0 and vice versa
0227   TTBV& flip(int pos) {
0228     bs_.flip(pos);
0229     return *this;
0230   }
0231 
0232   // manipulation: absolute value of biased twos' complement. Converts twos' complenet into binary.
0233   TTBV& abs() {
0234     if (twos_) {
0235       twos_ = false;
0236       if (this->msb())
0237         this->flip();
0238       size_--;
0239     }
0240     return *this;
0241   }
0242 
0243   // manipulation: resize
0244   TTBV& resize(int size) {
0245     bool msb = this->msb();
0246     if (size > size_) {
0247       if (twos_)
0248         for (int n = size_; n < size; n++)
0249           bs_.set(n, msb);
0250       size_ = size;
0251     } else if (size < size_ && size > 0) {
0252       this->operator<<=(size_ - size);
0253       if (twos_)
0254         this->msb() = msb;
0255     }
0256     return *this;
0257   }
0258 
0259   // conversion: to string
0260   std::string str() const { return bs_.to_string().substr(S_ - size_, S_); }
0261 
0262   // conversion: range based to string
0263   std::string str(int start, int end = 0) const { return this->str().substr(size_ - start, size_ - end); }
0264 
0265   // conversion: to int
0266   int val() const { return (twos_ && this->msb()) ? (int)bs_.to_ullong() - iMax() : bs_.to_ullong(); }
0267 
0268   // conversion: to int, reinterpret sign
0269   int val(bool twos) const { return (twos && this->msb()) ? (int)bs_.to_ullong() - iMax() : bs_.to_ullong(); }
0270 
0271   // conversion: range based to int, reinterpret sign
0272   int val(int start, int end = 0, bool twos = false) const { return TTBV(*this, start, end).val(twos); }
0273 
0274   // conversion: to double for given precision assuming biased (floor) representation
0275   double val(double base) const { return (this->val() + .5) * base; }
0276 
0277   // conversion: range based to double for given precision assuming biased (floor) representation, reinterpret sign
0278   double val(double base, int start, int end = 0, bool twos = false) const {
0279     return (this->val(start, end, twos) + .5) * base;
0280   }
0281 
0282   // maniplulation and conversion: extracts range based to double reinterpret sign and removes these bits
0283   double extract(double base, int size, bool twos = false) {
0284     double val = this->val(base, size, 0, twos);
0285     this->operator>>=(size);
0286     return val;
0287   }
0288 
0289   // maniplulation and conversion: extracts range based to int reinterpret sign and removes these bits
0290   int extract(int size, bool twos = false) {
0291     int val = this->val(size, 0, twos);
0292     this->operator>>=(size);
0293     return val;
0294   }
0295 
0296   // maniplulation and conversion: extracts bool and removes this bit
0297   bool extract() {
0298     bool val = bs_[0];
0299     this->operator>>=(1);
0300     return val;
0301   }
0302 
0303   // manipulation: extracts slice and removes these bits
0304   TTBV slice(int size, bool twos = false) {
0305     TTBV ttBV(*this, size, 0, twos);
0306     this->operator>>=(size);
0307     return ttBV;
0308   }
0309 
0310   // range based count of '1's or '0's
0311   int count(int begin, int end, bool b = true) const {
0312     int c(0);
0313     for (int i = begin; i < end; i++)
0314       if (bs_[i] == b)
0315         c++;
0316     return c;
0317   }
0318 
0319   // position of least significant '1' or '0'
0320   int plEncode(bool b = true) const {
0321     for (int e = 0; e < size_; e++)
0322       if (bs_[e] == b)
0323         return e;
0324     return size_;
0325   }
0326 
0327   // position of least significant '1' or '0' in range [begin, end)
0328   int plEncode(int begin, int end, bool b = true) const {
0329     for (int e = begin; e < end; e++)
0330       if (bs_.test(e) == b)
0331         return e;
0332     return size_;
0333   }
0334 
0335   // position of most significant '1' or '0'
0336   int pmEncode(bool b = true) const {
0337     for (int e = size_ - 1; e > -1; e--)
0338       if (bs_[e] == b)
0339         return e;
0340     return size_;
0341   }
0342 
0343   // position of most significant '1' or '0' in range [begin, end)
0344   int pmEncode(int begin, int end, bool b = true) const {
0345     for (int e = end - 1; e >= begin; e--)
0346       if (bs_.test(e) == b)
0347         return e;
0348     return end;
0349   }
0350 
0351   // position for n'th '1' or '0' counted from least to most significant bit
0352   int encode(int n, bool b = true) const {
0353     int sum(0);
0354     for (int e = 0; e < size_; e++) {
0355       if (bs_[e] == b) {
0356         sum++;
0357         if (sum == n)
0358           return e;
0359       }
0360     }
0361     return size_;
0362   }
0363 
0364   std::vector<int> ids(bool b = true, bool singed = false) const {
0365     std::vector<int> v;
0366     v.reserve(bs_.count());
0367     for (int i = 0; i < size_; i++)
0368       if (bs_[i] == b)
0369         v.push_back(singed ? i + size_ / 2 : i);
0370     return v;
0371   }
0372 
0373   friend std::ostream& operator<<(std::ostream& os, const TTBV& ttBV) { return os << ttBV.str(); }
0374 
0375 private:
0376   // look up table initializer for powers of 2
0377   constexpr std::array<double, S_ + 1> powersOfTwo() const {
0378     std::array<double, S_ + 1> lut = {};
0379     for (int i = 0; i <= S_; i++)
0380       lut[i] = std::pow(2, i);
0381     return lut;
0382   }
0383 
0384   // returns 2 ** size_
0385   double iMax() const {
0386     static const std::array<double, S_ + 1> lut = powersOfTwo();
0387     return std::round(lut[size_]);
0388   }
0389 
0390   // check if value fits into binary BV
0391   void checkU(unsigned long long int value) {
0392     if (size_ <= 0 || size_ > S_)
0393       throwSize();
0394     if (value < iMax())
0395       return;
0396     cms::Exception exception("RunTimeError.");
0397     exception << "Value " << value << " does not fit into a " << size_ << "b binary.";
0398     exception.addContext("TTBV::checkU");
0399     throw exception;
0400   }
0401 
0402   // check if value fits into twos's complement BV
0403   void checkT(int value) {
0404     static const std::array<double, S_ + 1> lut = powersOfTwo();
0405     auto abs = [](int val) { return val < 0 ? std::abs(val) - 1 : val; };
0406     if (abs(value) < std::round(lut[size_ - 1]))
0407       return;
0408     cms::Exception exception("RunTimeError.");
0409     exception << "Value " << value << " does not fit into a " << size_ << "b two's complement.";
0410     exception.addContext("TTBV::checkT");
0411     throw exception;
0412   }
0413 
0414   // check if value fits into twos complement / binary BV
0415   void checkI(int value) {
0416     if (size_ <= 0 || size_ > S_)
0417       throwSize();
0418     if (twos_)
0419       checkT(value);
0420     else if (value < 0) {
0421       cms::Exception exception("RunTimeError.");
0422       exception << size_ << "b Binary TTBV constructor called with negative value (" << value << ").";
0423       exception.addContext("TTBV::checkI");
0424       throw exception;
0425     } else
0426       checkU(value);
0427   }
0428 
0429   // nonsensical bitwith of smaller equal 0 or unsupported size, bigger 64, deteced
0430   void throwSize() const {
0431     cms::Exception exception("RunTimeError.");
0432     exception << "TTBV constructor called with bad bit width (" << size_ << ").";
0433     throw exception;
0434   }
0435 };
0436 
0437 #endif