Advertisement
andybuckley

A simple binned storage implementation with bisection lookup

Oct 12th, 2013
145
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.66 KB | None | 0 0
  1. // This is a pretty simple implementation of a "binning", which allows you to store objects of any
  2. // type TY in an axis denominated in any variable TX, with lookup of the bin at position x using the
  3. // bisection std::upper_bound function. It allows irregular binnings, but not *gaps* in the binning.
  4. // This can be made faster, e.g. by guessing at uniform binnings first, using linear search below a // certain problem size, etc., but it gets quite a bit more fiddly than I want to write on a Saturday // afternoon! See https://yoda.hepforge.org/trac/browser/include/YODA/Utils/BinSearcher.h for that.
  5.  
  6. // Definition... normally in Binning.h header file
  7. // #pragma once
  8.  
  9. #include <cstddef>
  10. #include <vector>
  11. #include <algorithm>
  12. #include <stdexcept>
  13. #include <cassert>
  14.  
  15. template <typename TY, typename TX=double>
  16. class Binning {
  17. public:
  18.  
  19.   /// Constructor taking a list of bin edges
  20.   Binning(const std::vector<TX>& binedges)
  21.     : edges(binedges)
  22.   {
  23.     reset();
  24.   }
  25.  
  26.   /// Constructor taking lists of bin edges and values
  27.   Binning(const std::vector<TX>& binedges, const std::vector<TY>& binvalues)
  28.     : edges(binedges), values(binvalues)
  29.   {
  30.     check();
  31.   }
  32.  
  33.   /// Get the bin index enclosing position @a x
  34.   size_t get_index(const TX& x) const {
  35.     check();
  36.     if (x < edges.front()) throw std::out_of_range("x value underflow");
  37.     if (x > edges.back()) throw std::out_of_range("x value overflow");
  38.     // Find the closest knot below the requested value
  39.     size_t i = upper_bound(edges.begin(), edges.end(), x) - edges.begin();
  40.     if (i == edges.size()) i -= 1; // can't return the last knot index
  41.     i -= 1; // have to step back to get the knot <= x behaviour
  42.     return i;
  43.   }
  44.  
  45.   /// Get the value in bin number @a ix
  46.   const TY& get_at_index(size_t ix) const {
  47.     check();
  48.     return values[ix];
  49.   }
  50.  
  51.   /// Get the value in the bin at position @a x
  52.   const TY& get_at(const TX& x) const {
  53.     return get_at_index(get_index(x));
  54.   }
  55.  
  56.   /// Get the value in bin number @a ix
  57.   void set_at_index(size_t ix, const TY& val) {
  58.     check();
  59.     values[ix] = val;
  60.   }
  61.  
  62.   /// Get the value in the bin at position @a x
  63.   void set_at(const TX& x, const TY& val) {
  64.     set_at_index(get_index(x), val);
  65.   }
  66.  
  67.   /// Get the number of bins
  68.   size_t num_bins() {
  69.     check();
  70.     return values.size();
  71.   }
  72.  
  73.   /// Clear the bin contents (but leave the binning intact)
  74.   void reset() {
  75.     assert(edges.size() > 1);
  76.     values.clear();
  77.     values.resize(edges.size()-1);
  78.     check();
  79.   }
  80.  
  81.   /// Check consistency of the edges and values vectors
  82.   void check() const {
  83.     if (edges.size() <= 1) throw std::length_error("There must be 2 or more bin edges");
  84.     if (values.size() < 1) throw std::length_error("There must be 1 or more bin values");
  85.     if (edges.size()-1 != values.size()) throw std::length_error("There must be one more bin edge than there are bin values");
  86.   }
  87.  
  88.   /// The list of bin edges
  89.   std::vector<TX> edges;
  90.  
  91.   /// The list of values
  92.   std::vector<TY> values;
  93.  
  94. };
  95.  
  96. //////////////////////////////////////
  97. // And usage... normally from a separate .cc file
  98.  
  99. // #include "Binning.h"
  100. #include <iostream>
  101. using namespace std;
  102.  
  103. struct F {
  104.   F(int a) : i(a) {}
  105.   int i;
  106. };
  107. ostream& operator << (ostream& os, const F& f) { os << "F" << f.i; return os; }
  108.  
  109. int main() {
  110.   Binning<float> b1({{0,1,2,3,4,5}}, {{10,20,30,40,50}});
  111.   cout << b1.get_index(3.3) << endl;
  112.   cout << b1.get_at(3.3) << endl;
  113.   cout << b1.get_at_index(3) << endl;
  114.  
  115.   Binning<F> b2({{0,1,2,3,4,5}}, {{10,20,30,40,50}});
  116.   cout << b2.get_index(2.3) << endl;
  117.   cout << b2.get_at(2.3) << endl;
  118.   cout << b2.get_at_index(2) << endl;
  119.  
  120.   return 0;
  121. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement