yoda is hosted by Hepforge, IPPP Durham
YODA - Yet more Objects for Data Analysis 2.0.0
YODA::Axis< T, isCAxis< T > > Class Template Reference

Continuous axis with floating-point-type edges. More...

#include <BinnedAxis.h>

Public Types

using EdgeT = T
 
using ContainerT = std::vector< T >
 
using const_iterator = typename ContainerT::const_iterator
 
using CAxisT = isCAxis< T >
 

Public Member Functions

 Axis ()
 Nullary constructor for unique pointers etc.
 
 Axis (const Axis< T, CAxisT > &other)
 
 Axis (Axis< T, CAxisT > &&other)
 
 Axis (std::vector< EdgeT > edges)
 Constructs continuous Axis from a vector.
 
 Axis (std::initializer_list< T > &&edges)
 Constructs continuous Axis from an initializer list.
 
 Axis (std::vector< std::pair< EdgeT, EdgeT > > binsEdges)
 
 Axis (size_t nBins, EdgeT lower, EdgeT upper)
 
Axisoperator= (const Axis &other)
 
Axisoperator= (Axis &&other)
 
size_t index (const EdgeT &x) const
 Bin searcher.
 
size_t size () const noexcept
 Returns amount of bins in axis.
 
size_t numBins (const bool includeOverflows=false) const noexcept
 Returns amount of bins in axis.
 
EdgeT edge (const size_t i) const
 Returns edge corresponding to index.
 
std::vector< EdgeTedges () const noexcept
 Returns a copy of all axis edges. Includes -inf and +inf edges.
 
const_iterator begin () const
 Returns the const begin iterator for the edges container.
 
const_iterator end () const
 Returns the const end iterator for the edges container.
 
bool hasSameEdges (const Axis< EdgeT, CAxisT > &other) const noexcept
 Check if two BinnedAxis objects have the same edges.
 
std::vector< T > sharedEdges (const Axis< EdgeT, CAxisT > &other) const noexcept
 Find edges which are shared between BinnedAxis objects, within numeric tolerance.
 
bool isSubsetEdges (const Axis< EdgeT, CAxisT > &other) const noexcept
 Check if other axis edges are a subset of edges of this one.
 
std::vector< size_t > maskedBins () const noexcept
 Returns the masked indices.
 
I/O
std::string type () const noexcept
 Returns a string representation of EdgeT.
 
Transformations
void mergeBins (std::pair< size_t, size_t >)
 Merges bins, e.g. removes edges in between.
 
Space characteristics
std::vector< T > widths (const bool includeOverflows=false) const noexcept
 
EdgeT width (size_t binNum) const noexcept
 Width of bin side on this axis.
 
EdgeT max (size_t binNum) const noexcept
 Max of bin side on this axis.
 
EdgeT min (size_t binNum) const noexcept
 Min of bin side on this axis.
 
EdgeT mid (size_t binNum) const noexcept
 Mid of bin side on this axis.
 

Detailed Description

template<typename T>
class YODA::Axis< T, isCAxis< T > >

Continuous axis with floating-point-type edges.

Definition at line 326 of file BinnedAxis.h.

Member Typedef Documentation

◆ CAxisT

template<typename T >
using YODA::Axis< T, isCAxis< T > >::CAxisT = isCAxis<T>

Definition at line 331 of file BinnedAxis.h.

◆ const_iterator

template<typename T >
using YODA::Axis< T, isCAxis< T > >::const_iterator = typename ContainerT::const_iterator

Definition at line 330 of file BinnedAxis.h.

◆ ContainerT

template<typename T >
using YODA::Axis< T, isCAxis< T > >::ContainerT = std::vector<T>

Definition at line 329 of file BinnedAxis.h.

◆ EdgeT

template<typename T >
using YODA::Axis< T, isCAxis< T > >::EdgeT = T

Definition at line 328 of file BinnedAxis.h.

Constructor & Destructor Documentation

◆ Axis() [1/7]

template<typename T >
YODA::Axis< T, isCAxis< T > >::Axis ( )
inline

Nullary constructor for unique pointers etc.

Definition at line 334 of file BinnedAxis.h.

334 {
335 _updateEdges({});
336 _setEstimator();
337 }

◆ Axis() [2/7]

template<typename T >
YODA::Axis< T, isCAxis< T > >::Axis ( const Axis< T, CAxisT > &  other)

Concept check shall appear inside body of type's member function or outside of type, since otherwise type is considered incomplete.

Note
Concept check appears once to check whether the type Axis satisfies the concept.

Definition at line 560 of file BinnedAxis.h.

560 {
565 static_assert(MetaUtils::checkConcept<Axis<EdgeT>, YODAConcepts::AxisImpl>(),
566 "Axis<T> should implement Axis concept.");
567
568 _est = other._est;
569 _edges = other._edges;
570 _maskedBins = other._maskedBins;
571 }

◆ Axis() [3/7]

template<typename T >
YODA::Axis< T, isCAxis< T > >::Axis ( Axis< T, CAxisT > &&  other)
inline

Definition at line 341 of file BinnedAxis.h.

342 : _est(other._est),
343 _maskedBins(std::move(other._maskedBins)),
344 _edges(std::move(other._edges)) {}

◆ Axis() [4/7]

template<typename T >
YODA::Axis< T, isCAxis< T > >::Axis ( std::vector< EdgeT edges)

Constructs continuous Axis from a vector.

Note
Edges are sorted on construction stage.

Definition at line 642 of file BinnedAxis.h.

642 {
643 std::sort(edges.begin(), edges.end());
644 edges.erase( std::unique(edges.begin(), edges.end()), edges.end() );
645
646 _updateEdges(std::move(edges));
647
648 _setEstimator();
649 }
std::vector< EdgeT > edges() const noexcept
Returns a copy of all axis edges. Includes -inf and +inf edges.
Definition BinnedAxis.h:702

◆ Axis() [5/7]

template<typename T >
YODA::Axis< T, isCAxis< T > >::Axis ( std::initializer_list< T > &&  edges)

Constructs continuous Axis from an initializer list.

Note
Edges are sorted on construction stage

Definition at line 652 of file BinnedAxis.h.

652 {
653 std::vector<T> edges{edgeList};
654 std::sort(edges.begin(), edges.end());
655 edges.erase( std::unique(edges.begin(), edges.end()), edges.end() );
656
657 _updateEdges(std::move(edges));
658
659 _setEstimator();
660 }

◆ Axis() [6/7]

template<typename T >
YODA::Axis< T, isCAxis< T > >::Axis ( std::vector< std::pair< EdgeT, EdgeT > >  binsEdges)
Note
Vector shouldn't contain any intersecting pairs, e.g. pair1.second > pair2.first. Order of pairs does not matter. BinsEdges is sorted on construction stage.

Merge if equal

Note
If there is a gap, mark bin as masked.

In case there have been merges. +1 to account for +inf.

Definition at line 594 of file BinnedAxis.h.

594 {
595 if (binsEdges.empty()) throw BinningError("Expected at least one discrete edge");
596
597 std::sort(binsEdges.begin(), binsEdges.end(), [](auto &left, auto &right) {
598 return left.first < right.first;
599 });
600
601 _edges.resize(binsEdges.size()*2+2);
602
603 _edges[0] = -std::numeric_limits<double>::infinity();
604
605
606 /* Edges pairs from binsEdges vector
613 */
614
615 size_t i = 1;
616 for (const auto& pair : binsEdges) {
617 if (!fuzzyGtrEquals(pair.first, _edges[i-1])) throw BinningError("Bin edges shouldn't intersect");
618 if (i == 1 && std::isinf(pair.first) && pair.first < 0) {
619 _edges[i++] = pair.second;
620 continue;
621 }
622 if (fuzzyEquals(pair.first, _edges[i-1])) {
623 _edges[i++] = pair.second;
624 continue;
625 }
626 if (i != 1 && pair.first > _edges[i-1]) {
628 _maskedBins.emplace_back(i-1);
629 }
630 _edges[i++] = pair.first;
631 _edges[i++] = pair.second;
632 }
633
634 _edges[i] = std::numeric_limits<double>::infinity();
635
636 _edges.resize(i+1);
637
638 _setEstimator();
639 }
std::enable_if_t< std::is_arithmetic_v< N1 > &&std::is_arithmetic_v< N2 >, bool > fuzzyGtrEquals(N1 a, N2 b, double tolerance=1e-5)
Compare two numbers for >= with a degree of fuzziness.
Definition MathUtils.h:125
std::enable_if_t< std::is_arithmetic_v< N1 > &&std::is_arithmetic_v< N2 > &&(std::is_floating_point_v< N1 >||std::is_floating_point_v< N2 >), bool > fuzzyEquals(N1 a, N2 b, double tolerance=1e-5)
Compare two numbers for equality with a degree of fuzziness.
Definition MathUtils.h:96

References YODA::fuzzyEquals(), and YODA::fuzzyGtrEquals().

◆ Axis() [7/7]

template<typename T >
YODA::Axis< T, isCAxis< T > >::Axis ( size_t  nBins,
EdgeT  lower,
EdgeT  upper 
)

Definition at line 574 of file BinnedAxis.h.

574 {
575 if(upper <= lower)
576 throw(std::logic_error("Upper bound should be larger than lower."));
577 _edges.resize(nBins+1+2);
578 double step = (upper - lower) / nBins;
579
580 _edges[0] = -std::numeric_limits<double>::infinity();
581
582 _edges[1] = lower;
583
584 for(size_t i = 2; i < _edges.size()-1; i++) {
585 _edges[i] = _edges[i-1] + step;
586 }
587
588 _edges[_edges.size()-1] = std::numeric_limits<double>::infinity();
589
590 _setEstimator();
591 }

Member Function Documentation

◆ begin()

template<typename T >
const_iterator YODA::Axis< T, isCAxis< T > >::begin ( ) const
inline

Returns the const begin iterator for the edges container.

Definition at line 425 of file BinnedAxis.h.

425{ return _edges.cbegin(); }

◆ edge()

template<typename T >
Axis< T, isCAxis< T > >::EdgeT YODA::Axis< T, isCAxis< T > >::edge ( const size_t  i) const

Returns edge corresponding to index.

Definition at line 697 of file BinnedAxis.h.

697 {
698 return this->_edges.at(i);
699 }

◆ edges()

template<typename T >
std::vector< typename Axis< T, isCAxis< T > >::EdgeT > YODA::Axis< T, isCAxis< T > >::edges ( ) const
noexcept

Returns a copy of all axis edges. Includes -inf and +inf edges.

Definition at line 702 of file BinnedAxis.h.

702 {
703 return this->_edges;
704 }

◆ end()

template<typename T >
const_iterator YODA::Axis< T, isCAxis< T > >::end ( ) const
inline

Returns the const end iterator for the edges container.

Definition at line 428 of file BinnedAxis.h.

428{ return _edges.cend(); }

◆ hasSameEdges()

template<typename T >
bool YODA::Axis< T, isCAxis< T > >::hasSameEdges ( const Axis< EdgeT, CAxisT > &  other) const
noexcept

Check if two BinnedAxis objects have the same edges.

Todo:
Be careful about using fuzzyEquals... should be an exact comparison?

Definition at line 707 of file BinnedAxis.h.

707 {
708 if (this->numBins(true) != other.numBins(true)) return false;
709 for (size_t i = 1; i < this->numBins(true) - 1; i++) {
711 if (!fuzzyEquals(edge(i), other.edge(i))) return false;
712 }
713 return true;
714 }
EdgeT edge(const size_t i) const
Returns edge corresponding to index.
Definition BinnedAxis.h:697
size_t numBins(const bool includeOverflows=false) const noexcept
Returns amount of bins in axis.
Definition BinnedAxis.h:691

References YODA::fuzzyEquals().

◆ index()

template<typename T >
size_t YODA::Axis< T, isCAxis< T > >::index ( const EdgeT x) const

Bin searcher.

Author
David Mallows
Andy Buckley

Handles low-level bin lookups using a hybrid algorithm that is considerably faster for regular (logarithmic or linear) and near-regular binnings. Comparable performance for irregular binnings.

The reason this works is that linear search is faster than bisection search up to about 32-64 elements. So we make a guess, and we then do a linear search. If that fails, then we bisect on the remainder, terminating once bisection search has got the range down to about 32. So we actually pay for the fanciness of predicting the bin out of speeding up the bisection search by finishing it with a linear search. So in most cases, we get constant-time lookups regardless of the space.

Definition at line 663 of file BinnedAxis.h.

663 {
664 if (_edges.size() <= 2) throw BinningError("Axis initialised without specifying edges");
665 // Check overflows
666 if (std::isinf(x)) { return x < 0? 0 : _edges.size() - 2; }
667 // Get initial estimate
668 size_t index = std::min(_est->estindex(x), _edges.size()-2);
669 // Return now if this is the correct bin
670 if (x >= this->_edges[index] && x < this->_edges[index+1]) return index;
671
672 // Otherwise refine the estimate, if x is not exactly on a bin edge
673 if (x > this->_edges[index]) {
674 const ssize_t newindex = _linsearch_forward(index, x, SEARCH_SIZElc);
675 index = (newindex > 0) ? newindex : _bisect(x, index, this->_edges.size()-1);
676 } else if (x < this->_edges[index]) {
677 const ssize_t newindex = _linsearch_backward(index, x, SEARCH_SIZElc);
678 index = (newindex > 0) ? newindex : _bisect(x, 0, index+1);
679 }
680
681 assert(x >= this->_edges[index] && (x < this->_edges[index+1] || std::isinf(x)));
682 return index;
683 }
size_t index(const EdgeT &x) const
Bin searcher.
Definition BinnedAxis.h:663
size_t size() const noexcept
Returns amount of bins in axis.
Definition BinnedAxis.h:686
const size_t SEARCH_SIZElc
Definition BinnedAxis.h:28

References YODA::SEARCH_SIZElc.

◆ isSubsetEdges()

template<typename T >
bool YODA::Axis< T, isCAxis< T > >::isSubsetEdges ( const Axis< EdgeT, CAxisT > &  other) const
noexcept

Check if other axis edges are a subset of edges of this one.

Remarks
Should it be symmetrical? E.g. ax1.subsetEdges(ax2) == ax2.subsetEdges(ax1)?

Skip if any of axes only has two limit edges

Note
std::includes demands sorted ranges

Since one of the axes consists only of limits (-inf, +inf), it's a subset of the other one

Definition at line 740 of file BinnedAxis.h.

740 {
741 if (_edges.size() == other._edges.size()) return hasSameEdges(other);
742
744 if (_edges.size() > 2 && other._edges.size() > 2) {
746 return std::includes(std::next(_edges.begin()), std::prev(_edges.end()),
747 std::next(other._edges.begin()), std::prev(other._edges.end()));
748 }
749
752 return true;
753 }
bool hasSameEdges(const Axis< EdgeT, CAxisT > &other) const noexcept
Check if two BinnedAxis objects have the same edges.
Definition BinnedAxis.h:707

◆ maskedBins()

template<typename T >
std::vector< size_t > YODA::Axis< T, isCAxis< T > >::maskedBins ( ) const
inlinenoexcept

Returns the masked indices.

Definition at line 442 of file BinnedAxis.h.

442{ return _maskedBins; }

◆ max()

template<typename T >
EdgeT YODA::Axis< T, isCAxis< T > >::max ( size_t  binNum) const
inlinenoexcept

Max of bin side on this axis.

Definition at line 503 of file BinnedAxis.h.

503 {
504 return _edges[binNum+1];
505 }

◆ mergeBins()

template<typename T >
void YODA::Axis< T, isCAxis< T > >::mergeBins ( std::pair< size_t, size_t >  mergeRange)

Merges bins, e.g. removes edges in between.

Note
At least 1 non-overflow bin must exist after merging.

Definition at line 756 of file BinnedAxis.h.

756 {
757 if (_edges.size() <= 2) throw BinningError("Axis initialised without specifying edges");
758 if (mergeRange.second < mergeRange.first) throw RangeError("Upper index comes before lower index");
759 if (mergeRange.second >= numBins(true)) throw RangeError("Upper index exceeds last visible bin");
760 _edges.erase(_edges.begin()+mergeRange.first+1, _edges.begin() + mergeRange.second + 1);
761 // masked bins above the merge range need to be re-indexed
762 // masked bins within the merge range need to be unmasked
763 std::vector<size_t> toRemove;
764 size_t mrange = mergeRange.second - mergeRange.first;
765 for (size_t i = 0; i < _maskedBins.size(); ++i) {
766 if (_maskedBins[i] > mergeRange.second) _maskedBins[i] -= mrange;
767 else if (_maskedBins[i] >= mergeRange.first) toRemove.push_back(_maskedBins[i]);
768 }
769 if (toRemove.size()) {
770 _maskedBins.erase(
771 std::remove_if(_maskedBins.begin(), _maskedBins.end(), [&](const auto& idx) {
772 return std::find(toRemove.begin(), toRemove.end(), idx) != toRemove.end();
773 }), _maskedBins.end());
774 }
775 }

◆ mid()

template<typename T >
EdgeT YODA::Axis< T, isCAxis< T > >::mid ( size_t  binNum) const
inlinenoexcept

Mid of bin side on this axis.

Note
Corner bins are overflow bins, thus infinite limit values.

Definition at line 514 of file BinnedAxis.h.

514 {
516 if(binNum == 0)
517 return std::numeric_limits<EdgeT>::min();
518 if (binNum == (numBins(true) - 1))
519 return std::numeric_limits<EdgeT>::max();
520
521 EdgeT minVal = min(binNum);
522 return (max(binNum) - minVal)/2 + minVal;
523 }
EdgeT min(size_t binNum) const noexcept
Min of bin side on this axis.
Definition BinnedAxis.h:509
EdgeT max(size_t binNum) const noexcept
Max of bin side on this axis.
Definition BinnedAxis.h:503

◆ min()

template<typename T >
EdgeT YODA::Axis< T, isCAxis< T > >::min ( size_t  binNum) const
inlinenoexcept

Min of bin side on this axis.

Definition at line 509 of file BinnedAxis.h.

509 {
510 return _edges[binNum];
511 }

◆ numBins()

template<typename T >
size_t YODA::Axis< T, isCAxis< T > >::numBins ( const bool  includeOverflows = false) const
noexcept

Returns amount of bins in axis.

Definition at line 691 of file BinnedAxis.h.

691 {
692 if (_edges.size() < 3) return 0; // no visible bin edge
693 return this->_edges.size() - (includeOverflows? 1 : 3); // has 2 extra edges for +-inf
694 }

References YODA::Axis< T, typename >::size().

◆ operator=() [1/2]

template<typename T >
Axis & YODA::Axis< T, isCAxis< T > >::operator= ( Axis< T, isCAxis< T > > &&  other)
inline

Definition at line 372 of file BinnedAxis.h.

372 {
373 if (this != &other) {
374 _est = std::move(other._est);
375 _maskedBins = std::move(other._maskedBins);
376 _edges = std::move(other._edges);
377 }
378 return *this;
379 }

◆ operator=() [2/2]

template<typename T >
Axis & YODA::Axis< T, isCAxis< T > >::operator= ( const Axis< T, isCAxis< T > > &  other)
inline

Definition at line 363 of file BinnedAxis.h.

363 {
364 if (this != &other) {
365 _est = other._est;
366 _maskedBins = other._maskedBins;
367 _edges = other._edges;
368 }
369 return *this;
370 }

◆ sharedEdges()

template<typename T >
std::vector< T > YODA::Axis< T, isCAxis< T > >::sharedEdges ( const Axis< EdgeT, CAxisT > &  other) const
noexcept

Find edges which are shared between BinnedAxis objects, within numeric tolerance.

Note
The return vector is sorted and includes -inf and inf

Skip if any of axes only has two limit edges

Definition at line 717 of file BinnedAxis.h.

717 {
718 std::vector<T> intersection;
719
721 if (_edges.size() > 2 && other._edges.size() > 2) {
722 std::set_intersection(std::next(_edges.begin()), std::prev(_edges.end()),
723 std::next(other._edges.begin()), std::prev(other._edges.end()),
724 std::back_inserter(intersection));
725 }
726
727 std::vector<T> rtn;
728 rtn.reserve(intersection.size()+2);
729
730 rtn.emplace_back(-std::numeric_limits<Axis<T, isCAxis<T>>::EdgeT>::infinity());
731 rtn.insert(std::next(rtn.begin()),
732 std::make_move_iterator(intersection.begin()),
733 std::make_move_iterator(intersection.end()));
734 rtn.emplace_back(std::numeric_limits<Axis<T, isCAxis<T>>::EdgeT>::infinity());
735
736 return rtn;
737 }
Axis()
Nullary constructor for unique pointers etc.
Definition BinnedAxis.h:334

◆ size()

template<typename T >
size_t YODA::Axis< T, isCAxis< T > >::size ( ) const
noexcept

Returns amount of bins in axis.

Definition at line 686 of file BinnedAxis.h.

686 {
687 return numBins(true); // number of visible + 2 for +-inf
688 }

◆ type()

template<typename T >
std::string YODA::Axis< T, isCAxis< T > >::type ( ) const
inlinenoexcept

Returns a string representation of EdgeT.

Definition at line 467 of file BinnedAxis.h.

467{ return TypeID<EdgeT>::name(); }
static const char * name()

◆ width()

template<typename T >
EdgeT YODA::Axis< T, isCAxis< T > >::width ( size_t  binNum) const
inlinenoexcept

Width of bin side on this axis.

Definition at line 498 of file BinnedAxis.h.

498 {
499 return _edges[binNum+1] - _edges[binNum];
500 }

◆ widths()

template<typename T >
std::vector< T > YODA::Axis< T, isCAxis< T > >::widths ( const bool  includeOverflows = false) const
inlinenoexcept

Definition at line 484 of file BinnedAxis.h.

484 {
485 // number of widths = number of edges - 1
486 // unless you exclude under-/overflow
487 size_t offset = includeOverflows? 1 : 3;
488 std::vector<T> ret(_edges.size()-offset);
489 size_t start = 1 + !includeOverflows;
490 size_t end = _edges.size() - !includeOverflows;
491 for (size_t i = start; i < end; ++i) {
492 ret[i-start] = _edges[i] - _edges[i-1];
493 }
494 return ret;
495 }
const_iterator end() const
Returns the const end iterator for the edges container.
Definition BinnedAxis.h:428

The documentation for this class was generated from the following file: