Hammer  1.0.0
Helicity Amplitude Module for Matrix Element Reweighting
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AlignedIndexing.cc
Go to the documentation of this file.
1 ///
2 /// @file AlignedIndexing.cc
3 /// @brief Sparse tensor indexer
4 ///
5 
6 //**** This file is a part of the HAMMER library
7 //**** Copyright (C) 2016 - 2020 The HAMMER Collaboration
8 //**** HAMMER is licensed under version 3 of the GPL; see COPYING for details
9 //**** Please note the MCnet academic guidelines; see GUIDELINES for details
10 
11 // -*- C++ -*-
12 #include <numeric>
13 #include <functional>
14 #include <iostream>
15 #include <algorithm>
16 
18 #include "Hammer/Exceptions.hh"
19 #include "Hammer/Tools/Utils.hh"
20 #include "Hammer/Math/Utils.hh"
21 
22 using namespace std;
23 
24 namespace Hammer {
25 
26  namespace MultiDimensional {
27 
29  if (value == 0)
30  return value;
31  if (value == 1)
32  return 0;
33  --value;
34  value = static_cast<IndexType>(value | (value >> 1));
35  value = static_cast<IndexType>(value | (value >> 2));
36  value = static_cast<IndexType>(value | (value >> 4));
37  value = static_cast<IndexType>(value | (value >> 8));
38  ++value;
39  return value;
40  }
41 
42  AlignedIndexing::AlignedIndexing()
43  : _dimensions{}, _alignPads{}, _alignMasks{}, _maxIndex{0}, _maxAlignedIndex{0}, _unalignedEntries{} {
44  }
45 
46  AlignedIndexing::AlignedIndexing(IndexList dimensions) : _dimensions{dimensions} {
47  calc();
48  }
49 
50  size_t AlignedIndexing::rank() const {
51  return _dimensions.size();
52  }
53 
55  if (index < _dimensions.size()) {
56  return _dimensions[index];
57  }
58  throw Hammer::RangeError("Index out of range for multidimensional object of rank " +
59  to_string(_dimensions.size()) + ": all your base are belong to us.");
60  }
61 
63  return _dimensions;
64  }
65 
67  return _maxIndex + 1;
68  }
69 
70  bool AlignedIndexing::checkValidIndices(const IndexList& indices) const {
71  bool valid = (indices.size() == _dimensions.size());
72  if (!valid)
73  return false;
74  valid = inner_product(indices.begin(), indices.end(), _dimensions.begin(), valid, logical_and<bool>(),
75  less<IndexType>());
76  return valid;
77  }
78 
79  bool AlignedIndexing::checkValidIndices(IndexList::const_iterator first, IndexList::const_iterator last) const {
80  bool valid = (distance(first,last) == static_cast<ptrdiff_t>(_dimensions.size()));
81  if (!valid)
82  return false;
83  valid = inner_product(first, last, _dimensions.begin(), valid, logical_and<bool>(),
84  less<IndexType>());
85  return valid;
86  }
87 
89  return indicesToPos(indices.begin(), indices.end());
90  }
91 
92  PositionType AlignedIndexing::indicesToPos(IndexList::const_iterator first,
93  IndexList::const_iterator last) const {
94  if (rank() == 1) {
95  return *first;
96  }
97  PositionType index = 0ul;
98  function<size_t(PositionType, IndexType)> opCombine = [](PositionType idx, IndexType pad) -> PositionType {
99  return idx << pad;
100  };
101  index = inner_product(first, last, _alignPads.begin(), index, plus<PositionType>(), opCombine);
102  return index;
103  }
104 
105  void AlignedIndexing::posToIndices(PositionType alignedPosition, IndexList& result) const {
106  ASSERT(alignedPosition <= _maxAlignedIndex);
107  result.clear();
108  auto itp = _alignPads.begin();
109  auto itm = _alignMasks.begin();
110  for (; itp != _alignPads.end(); ++itp, ++itm) {
111  result.push_back(static_cast<IndexType>((alignedPosition >> (*itp)) & (*itm)));
112  }
113  }
114 
115  IndexType AlignedIndexing::ithIndexInPos(PositionType alignedPosition, IndexType indexPosition) const {
116  ASSERT(indexPosition < _alignPads.size());
117  return static_cast<IndexType>((alignedPosition >> _alignPads[indexPosition]) & _alignMasks[indexPosition]);
118  }
119 
121  const IndexList& outerShiftsInnerPositions,
122  const vector<bool>& isOuter,
123  IndexList& innerList, vector<bool>& innerAdded, bool shouldCompare) const {
124  fill(innerAdded.begin(), innerAdded.end(), false);
125  PositionType newPos = 0ul;
126  for (size_t i = 0; i < _dimensions.size(); ++i) {
127  IndexType idx = static_cast<IndexType>((alignedPosition >> _alignPads[i]) & _alignMasks[i]);
128  if (isOuter[i]) {
129  newPos += static_cast<PositionType>(idx << outerShiftsInnerPositions[i]);
130  } else {
131  ASSERT(outerShiftsInnerPositions[i] < innerList.size());
132  if (!shouldCompare) {
133  size_t innerPos = outerShiftsInnerPositions[i];
134  if (innerAdded[innerPos] && innerList[innerPos] != idx) {
135  return numeric_limits<size_t>::max();
136  }
137  innerAdded[innerPos] = true;
138  innerList[innerPos] = idx;
139  } else if (innerList[outerShiftsInnerPositions[i]] != idx) {
140  return numeric_limits<size_t>::max();
141  }
142  }
143  }
144  return newPos;
145  }
146 
147  std::tuple<IndexList, std::vector<bool>, PositionType> AlignedIndexing::processShifts(const IndexPairList& pairs,
148  IndexPairMember which) const {
149  map<IndexType, IndexType> inners;
150  for (IndexType i = 0; i < pairs.size(); ++i) {
151  switch (which) {
153  inners.insert(make_pair(pairs[i].first, i));
154  break;
156  inners.insert(make_pair(pairs[i].second, i));
157  break;
159  inners.insert(make_pair(pairs[i].first, i));
160  inners.insert(make_pair(pairs[i].second, i));
161  break;
162  }
163  }
164  IndexList newDims;
165  newDims.reserve(_dimensions.size());
166  for(IndexType i=0; i< _dimensions.size(); ++i) {
167  newDims.push_back((inners.find(i) != inners.end()) ? '\0' : _dimensions[i]);
168  }
169  IndexList retIndices;
170  vector<bool> retBools(_dimensions.size(), true);
171  auto maxIdx = calcPadding(newDims, retIndices);
172  for (auto elem : inners) {
173  retIndices[elem.first] = elem.second;
174  retBools[elem.first] = false;
175  }
176  return make_tuple(retIndices, retBools, maxIdx+1);
177  }
178 
180  return aligned ? _maxAlignedIndex : _maxIndex;
181  }
182 
184  IndexList tmpPads;
185  tmpPads.reserve(dimensions.size());
186  transform(dimensions.rbegin(), dimensions.rend(), back_inserter(tmpPads),
187  [](IndexType val) -> IndexType { return minPadding(val); });
188  pads.clear();
189  pads.push_back(0);
190  partial_sum(tmpPads.begin(), tmpPads.end(), back_inserter(pads));
191  PositionType maxAlignedIndex = (1ul << pads.back()) - 1ul;
192  pads.pop_back();
193  reverse(pads.begin(), pads.end());
194  return maxAlignedIndex;
195  }
196 
197  void AlignedIndexing::calcMasks(const IndexList& dimensions, IndexList& masks) const {
198  masks.clear();
199  transform(dimensions.rbegin(), dimensions.rend(), back_inserter(masks),
200  [](IndexType val) -> IndexType { return (val == 1u) ? 0u : static_cast<IndexType>(nextPowerOf2(val) - 1u); });
201  reverse(masks.begin(), masks.end());
202  }
203 
205  if(_dimensions.size() == 0) {
206  _maxIndex = 0;
207  _maxAlignedIndex = 0;
208  _alignMasks.clear();
209  _alignPads.clear();
210  _unalignedEntries.clear();
211  return;
212  }
213  _maxIndex = accumulate(_dimensions.begin(), _dimensions.end(), 1ul, multiplies<size_t>()) - 1ul;
217  }
218 
219  void AlignedIndexing::calcUnaligned(const IndexList& dimensions, const IndexList& pads,
220  PosIndexPairList& unaligned) const {
221  unaligned.clear();
222  auto itd = dimensions.rbegin();
223  auto itp = pads.rbegin();
224  ++itp;
225  PositionType currentStride = 1;
226  for(; itp != pads.rend(); ++itd, ++itp) {
227  currentStride *= *itd;
228  if (*itd != 1 && nextPowerOf2(*itd) != *itd) {
229  unaligned.push_back(make_pair(currentStride, *itp));
230  }
231  }
232  reverse(unaligned.begin(), unaligned.end());
233  }
234 
236  PositionType result = alignedPosition;
237  PositionType reminder = result;
238  for (auto& elem : _unalignedEntries) {
239  PositionType tmp = reminder >> elem.second;
240  reminder -= (tmp << elem.second);
241  result += tmp * elem.first - (tmp << elem.second);
242  }
243  return result;
244  }
245 
247  PositionType result = position;
248  PositionType reminder = result;
249  for (auto& elem : _unalignedEntries) {
250  PositionType tmp = reminder / elem.first;
251  reminder -= (tmp * elem.first);
252  result += (tmp << elem.second) - (tmp * elem.first);
253  }
254  return result;
255  }
256 
258  IndexType indexValue) const {
259  if(indexPosition == 0) {
260  return static_cast<PositionType>(indexValue << _alignPads[0]) + alignedPosition;
261  }
262  PositionType tmp1 = alignedPosition >> _alignPads[indexPosition];
263  PositionType tmp2 = alignedPosition - (tmp1 << _alignPads[indexPosition]);
264  return (tmp1 << _alignPads[indexPosition - 1]) +
265  static_cast<PositionType>(indexValue << _alignPads[indexPosition]) + tmp2;
266  }
267 
269  IndexType indexValue) const {
270  auto res = div(static_cast<long>(position), static_cast<long>(stride));
271  return posToAlignedPos((static_cast<PositionType>(res.quot * _dimensions[indexPosition]) + indexValue) * stride + static_cast<PositionType>(res.rem));
272  }
273 
274  bool AlignedIndexing::isSameShape(const IndexList& indices) const {
275  if (rank() != indices.size())
276  return false;
277  return equal(_dimensions.begin(), _dimensions.end(), indices.begin());
278  }
279 
280  } // namespace MultiDimensional
281 
282 } // namespace Hammer
void calcMasks(const IndexList &dimensions, IndexList &masks) const
std::vector< PosIndexPair > PosIndexPairList
std::vector< IndexPair > IndexPairList
size_t PositionType
void calcUnaligned(const IndexList &dimensions, const IndexList &pads, PosIndexPairList &unaligned) const
#define ASSERT(x)
Definition: Exceptions.hh:95
PositionType extendPosition(PositionType position, PositionType stride, IndexType indexPosition, IndexType indexValue) const
extends an unaligned absolute position from a rank N-1 tensor to the corresponding aligned position f...
IndexList _alignPads
the strides for each tensor index (necessary to convert coordinates to position in _data) ...
IndexType ithIndexInPos(PositionType alignedPosition, IndexType indexPosition) const
extract the value of the i-th index from an absolute aligned position
static IndexType nextPowerOf2(IndexType value)
uint16_t IndexType
PositionType numValues() const
the number of elements (product of all the dimensions)
const IndexList & dims() const
get the dimensions of all the indices at once
size_t rank() const
rank of the tensor
Hammer exception definitions.
PositionType alignedPosToPos(PositionType alignedPosition) const
convert the absolute aligned position to the absolute unaligned position that can be used with a Sequ...
std::vector< IndexType > IndexList
PositionType calcPadding(const IndexList &dimensions, IndexList &pads) const
PositionType posToAlignedPos(PositionType position) const
convert the absolute unaligned position (e.g.
IndexType dim(IndexType index) const
dimension of a specific component
PositionType maxIndex(bool aligned=true) const
get the maximum allowed value for the absolute position
bool checkValidIndices(const IndexList &indices) const
check that the indices are within range for each component
void posToIndices(PositionType alignedPosition, IndexList &result) const
convert the absolute aligned position (in row-major convention) into the list of indices ...
IndexList _dimensions
the dimensions of each tensor index
std::enable_if< std::is_unsigned< T >::value &&std::is_integral< T >::value, T >::type minPadding(T value)
Definition: Math/Utils.hh:90
PositionType splitPosition(PositionType alignedPosition, const IndexList &outerShiftsInnerPositions, const std::vector< bool > &isOuter, IndexList &innerList, std::vector< bool > &innerAdded, bool shouldCompare=false) const
split an absolute aligned position by separating contracted and uncontracted indices and returning th...
PositionType indicesToPos(const IndexList &indices) const
convert the indices into the (aligned) position indicizing a sparse tensor container organized as row...
PositionType extendAlignedPosition(PositionType alignedPosition, IndexType indexPosition, IndexType indexValue) const
extends an aligned absolute position from a rank N-1 tensor to the corresponding aligned position for...
IndexList _alignMasks
the strides for each tensor index (necessary to convert coordinates to position in _data) ...
bool isSameShape(const BasicIndexing &other) const
Out-of-range error class.
Definition: Exceptions.hh:49
std::tuple< IndexList, std::vector< bool >, PositionType > processShifts(const IndexPairList &pairs, IndexPairMember which) const
build the input lists necessary for calling splitPosition based on which indices are being contracted...
Sparse tensor indexer.