LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
TensorIndices.h
Go to the documentation of this file.
1 
15 #ifndef LARDATA_UTILITIES_TENSORINDICES_H
16 #define LARDATA_UTILITIES_TENSORINDICES_H
17 
18 // C/C++ standard libraries
19 #include <cstddef> // std::size_t
20 #include <stdexcept> // std::out_of_range
21 #include <string> // std::to_string()
22 #include <type_traits> // std::enable_if
23 
24 namespace util {
25 
28 
30  using Index_t = std::ptrdiff_t;
31 
33  using DimSize_t = std::size_t;
34 
36  using LinIndex_t = std::size_t;
37 
38  }; // TensorIndicesBasicTypes
39 
40  // This is the class declaration; it has a specialisation for rank 1 and
41  // a generic implementation (valid for rank larger than 1).
42  template <unsigned int RANK>
44 
45  namespace details {
46  template <unsigned int RANK, unsigned int DIM>
48  } // namespace details
49 
57  template <>
58  class TensorIndices<1U> {
59  public:
61 
63 
65 
66  static constexpr unsigned int rank() { return 1U; }
67 
68  TensorIndices(DimSize_t dim) : dimSize(dim) {}
69 
70  template <
71  typename ITER,
73  TensorIndices(ITER dimIter) : TensorIndices(*dimIter)
74  {}
75 
76  LinIndex_t operator()(Index_t index) const { return index; }
77 
78  template <typename ITER>
80  operator()(ITER indexIter) const
81  {
82  return *indexIter;
83  }
84 
85  LinIndex_t at(Index_t index) const { return checkOuterIndex(index); }
86 
87  template <typename ITER>
89  ITER indexIter) const
90  {
91  return checkOuterIndex(*indexIter);
92  }
93 
94  bool has(Index_t index) const { return (index >= 0) && ((DimSize_t)index < size()); }
95 
96  template <typename ITER>
98  ITER indexIter) const
99  {
100  return (*indexIter >= 0) && ((DimSize_t)*indexIter < size());
101  }
102 
103  template <unsigned int DIM = 0>
104  DimSize_t size() const
105  {
106  return (DIM == 0) ? totalSize() : dim<DIM>();
107  }
108 
109  template <unsigned int DIM>
110  DimSize_t dim() const
111  {
112  static_assert(DIM == 0, "Invalid dimension requested");
113  return dimSize;
114  } // dim()
115 
116  template <unsigned int DIM>
117  bool hasIndex(Index_t index) const
118  {
119  static_assert(DIM == 0, "Invalid dimension requested");
120  return has(index);
121  }
122 
123  bool hasLinIndex(LinIndex_t linIndex) const { return has((Index_t)linIndex); }
124 
125  bool operator==(TensorIndices<1U> const& t) const { return t.size() == size(); }
126  bool operator!=(TensorIndices<1U> const& t) const { return t.size() != size(); }
127 
128  protected:
130  {
131  if (has(index)) return index; // good
132  throw std::out_of_range("Requested index " + std::to_string(index) +
133  " for a dimension of size " + std::to_string(size()));
134  }
135 
136  protected:
138  DimSize_t dim0() const { return dimSize; }
139 
140  private:
141  template <unsigned int R, unsigned int D>
143 
145 
147  DimSize_t totalSize() const { return dim0(); }
148 
149  }; // class TensorIndices<1>
150 
165  template <unsigned int RANK>
166  class TensorIndices : private TensorIndices<1U> {
167  static_assert(RANK > 1, "TensorIndices must have rank 1 or higher");
168 
170 
171  public:
174 
177 
180 
182  static constexpr unsigned int rank() { return RANK; }
183 
185  using MinorTensor_t = TensorIndices<rank() - 1>;
186 
199  template <typename... OTHERDIMS>
200  TensorIndices(DimSize_t first, OTHERDIMS... others)
201  : Base_t(first), m(others...), totSize(dim0() * m.size())
202  {}
203 
223  // only if ITER can be dereferenced into something convertible to DimSize_t
224  template <
225  typename ITER,
227  TensorIndices(ITER dimIter) : Base_t(dimIter), m(++dimIter), totSize(dim0() * m.size())
228  {}
229 
250  template <typename... OTHERINDICES>
251  LinIndex_t operator()(Index_t first, OTHERINDICES... others) const
252  {
253  return first * minorTensor().size() + minorTensor()(others...);
254  }
255 
275  template <typename ITER>
277  operator()(ITER indexIter) const
278  {
279  auto const baseSize = (*indexIter) * minorTensor().size();
280  return baseSize + minorTensor()(++indexIter);
281  }
282 
305  template <typename... OTHERINDICES>
306  LinIndex_t at(Index_t first, OTHERINDICES... others) const
307  {
308  return Base_t::checkOuterIndex(first) * minorTensor().size() + minorTensor().at(others...);
309  }
310 
332  template <typename ITER>
334  ITER indexIter) const
335  {
336  auto const baseSize = Base_t::checkOuterIndex(*indexIter) * minorTensor().size();
337  return baseSize + minorTensor()(++indexIter);
338  }
339 
364  template <typename... OTHERINDICES>
365  bool has(Index_t first, OTHERINDICES... others) const
366  {
367  return Base_t::has(first) && minorTensor().has(others...);
368  }
369 
392  template <typename ITER>
394  ITER indexIter) const
395  {
396  return Base_t::has(*indexIter) ? minorTensor().has(++indexIter) : false;
397  }
398 
406  template <unsigned int DIM>
407  DimSize_t dim() const
408  {
410  }
411 
436  template <unsigned int DIM>
437  bool hasIndex(Index_t index) const
438  {
439  return (index >= 0U) && ((DimSize_t)index < dim<DIM>());
440  }
441 
455  template <unsigned int DIM = 0>
456  DimSize_t size() const
457  {
458  return (DIM == 0) ? totalSize() : details::ExtractTensorDimension<rank(), DIM>::size(*this);
459  }
460 
462  bool hasLinIndex(LinIndex_t linIndex) const
463  {
464  return (linIndex >= 0U) && ((DimSize_t)linIndex < size());
465  }
466 
470  MinorTensor_t const& minorTensor() const { return m; }
471 
473  bool operator==(TensorIndices<RANK> const& t) const
474  {
475  return Base_t::operator==(t) && (minorTensor() == t.minorTensor());
476  }
477 
479  bool operator!=(TensorIndices<RANK> const& t) const
480  {
481  return Base_t::operator!=(t) || (minorTensor() != t.minorTensor());
482  }
483 
484  protected:
485  // need to be friend of the dimension extractor
486  template <unsigned int R, unsigned int D>
488 
491 
493  DimSize_t totalSize() const { return totSize; }
494 
495  }; // class TensorIndices<>
496 
498  template <unsigned int RANK1,
499  unsigned int RANK2,
500  typename = std::enable_if_t<(RANK1 != RANK2), bool>>
502  {
503  return false;
504  }
505 
507  template <unsigned int RANK1,
508  unsigned int RANK2,
509  typename = std::enable_if_t<(RANK1 != RANK2), bool>>
511  {
512  return true;
513  }
514 
528  template <typename... DIMS>
529  auto makeTensorIndices(DIMS... dims)
530  {
531  return TensorIndices<sizeof...(DIMS)>{TensorIndicesBasicTypes::DimSize_t(dims)...};
532  }
533 
536 
537 } // namespace util
538 
539 //------------------------------------------------------------------------------
540 //--- details implementation
541 //---
542 namespace util {
543  namespace details {
544 
561  template <unsigned int RANK, unsigned int DIM>
562  struct ExtractTensorDimension {
563  static_assert(RANK > DIM, "Invalid dimension requested");
565  {
567  }
568 
570  {
572  }
573 
574  }; // ExtractTensorDimension<>()
575 
576  template <unsigned int RANK>
577  struct ExtractTensorDimension<RANK, 0U> {
578  static_assert(RANK > 0, "Invalid rank 0 for TensorIndices");
580  {
581  return t.dim0();
582  }
583 
585  {
586  return t.size();
587  }
588 
589  }; // ExtractTensorDimension<RANK, 0>()
590 
591  } // namespace details
592 } // namespace util
593 
594 #endif // LARDATA_UTILITIES_TENSORINDICES_H
bool has(Index_t index) const
Definition: TensorIndices.h:94
DimSize_t dim() const
std::enable_if_t< std::is_convertible< decltype(*(ITER())), DimSize_t >::value, LinIndex_t > at(ITER indexIter) const
Definition: TensorIndices.h:88
Base_t::LinIndex_t LinIndex_t
Type of the linear index.
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:26
std::ptrdiff_t Index_t
Type of a single index in the tensor.
Definition: TensorIndices.h:30
bool operator==(TensorIndices< RANK1 > const &a, TensorIndices< RANK2 > const &b)
Comparison operator with tensors of different rank.
bool hasIndex(Index_t index) const
std::enable_if_t< std::is_convertible< decltype(*(ITER())), DimSize_t >::value, LinIndex_t > operator()(ITER indexIter) const
Definition: TensorIndices.h:80
static TensorIndicesBasicTypes::DimSize_t dim(TensorIndices< RANK > const &t)
Types for TensorIndices class.
Definition: TensorIndices.h:27
std::enable_if_t< std::is_convertible< decltype(*(ITER())), DimSize_t >::value, LinIndex_t > at(ITER indexIter) const
Returns the linear index corresponding to the tensor indices.
bool has(Index_t first, OTHERINDICES...others) const
Returns whether the specified set of indices is valid.
bool operator==(TensorIndices< 1U > const &t) const
DimSize_t dimSize
size of the largest dimension
DimSize_t dim0() const
Returns the size of the outer dimension.
TensorIndices(ITER dimIter)
Definition: TensorIndices.h:73
Base_t::Index_t Index_t
Type of a single index in the tensor.
DimSize_t totalSize() const
Returns the total size of this tensor.
TensorIndices(DimSize_t first, OTHERDIMS...others)
Constructor: initialises the dimension of the tensor.
DimSize_t size() const
bool hasLinIndex(LinIndex_t linIndex) const
unsigned int Index_t
Type to denote the index of the flag.
Definition: BitMask.h:59
std::enable_if_t< std::is_convertible< decltype(*(ITER())), DimSize_t >::value, bool > has(ITER indexIter) const
Definition: TensorIndices.h:97
DimSize_t dim() const
Returns the size of the specified dimension.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:101
bool hasIndex(Index_t index) const
Returns whether a index is valid within a specified dimension.
DimSize_t totalSize() const
Returns the total size of this tensor (the same as size())
Index_t checkOuterIndex(Index_t index) const
static TensorIndicesBasicTypes::DimSize_t dim(TensorIndices< RANK > const &t)
Converts a tensor element specification into a linear index.
Definition: TensorIndices.h:43
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
LinIndex_t operator()(Index_t first, OTHERINDICES...others) const
Returns the linear index corresponding to the tensor indices.
TensorIndicesBasicTypes::LinIndex_t LinIndex_t
Definition: TensorIndices.h:64
static TensorIndicesBasicTypes::DimSize_t size(TensorIndices< RANK > const &t)
std::enable_if_t< std::is_convertible< decltype(*(ITER())), DimSize_t >::value, LinIndex_t > operator()(ITER indexIter) const
Returns the linear index corresponding to the tensor indices.
std::size_t DimSize_t
Type of size of a dimension in the tensor.
Definition: TensorIndices.h:33
DimSize_t totSize
size of this tensor
TensorIndices(ITER dimIter)
Constructor: initialises the dimension of the tensor.
bool operator==(TensorIndices< RANK > const &t) const
Returns whether all sizes of the tensor t are the same as this one.
bool hasLinIndex(LinIndex_t linIndex) const
Returns whether the specified linear index is valid in this tensor.
double value
Definition: spectrum.C:18
TensorIndices(DimSize_t dim)
Definition: TensorIndices.h:68
TensorIndicesBasicTypes::Index_t Index_t
Definition: TensorIndices.h:60
MinorTensor_t m
the rest of the tensor indices
TensorIndicesBasicTypes::DimSize_t DimSize_t
Definition: TensorIndices.h:62
static constexpr unsigned int rank()
Rank of this tensor.
bool operator!=(TensorIndices< 1U > const &t) const
bool operator!=(TensorIndices< RANK > const &t) const
Returns whether any size of the tensor t is different from this one.
static constexpr unsigned int rank()
Definition: TensorIndices.h:66
DimSize_t size() const
Returns the size of the minor tensor.
auto makeTensorIndices(DIMS...dims)
Instantiates a TensorIndices class with the specified dimensions.
MinorTensor_t const & minorTensor() const
LinIndex_t operator()(Index_t index) const
Definition: TensorIndices.h:76
bool operator!=(TensorIndices< RANK1 > const &a, TensorIndices< RANK2 > const &b)
Comparison operator with tensors of different rank.
std::size_t LinIndex_t
Type of the linear index.
Definition: TensorIndices.h:36
LinIndex_t at(Index_t first, OTHERINDICES...others) const
Returns the linear index corresponding to the tensor indices.
LinIndex_t at(Index_t index) const
Definition: TensorIndices.h:85
static TensorIndicesBasicTypes::DimSize_t size(TensorIndices< RANK > const &t)
std::enable_if_t< std::is_convertible< decltype(*(ITER())), DimSize_t >::value, bool > has(ITER indexIter) const
Returns whether the specified set of indices is valid.
Base_t::DimSize_t DimSize_t
Type for the specification of a dimension size.