Hammer  1.0.0
Helicity Amplitude Module for Matrix Element Reweighting
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BlockIndexing.cc
Go to the documentation of this file.
1 ///
2 /// @file BlockIndexing.cc
3 /// @brief Outer product 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 <type_traits>
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 
28  BlockIndexing::BlockIndexing()
29  : _subIndexing{}, _splitIndices{0}, _splitPads{0} {
30  }
31 
32  BlockIndexing::BlockIndexing(const vector<IndexList>& dims, const vector<LabelsList>& labels) {
33  auto itd = dims.begin();
34  auto itl = labels.begin();
35  for (; itd != dims.end(); ++itd, ++itl) {
36  _subIndexing.push_back(LabeledIndexing<AlignedIndexing>{*itd, *itl});
37  }
38  calc();
39  }
40 
42  LabeledIndexing<AlignedIndexing> right) : _subIndexing{left,right} {
43  calc();
44  }
45 
46  size_t BlockIndexing::rank() const {
47  return _globalIndexing.rank();
48  }
49 
51  try {
52  return _globalIndexing.dim(index);
53  }
54  catch(Hammer::RangeError&) {
55  throw Hammer::RangeError("Index out of range for multidimensional object of rank " + to_string(rank()) +
56  ": all your base are belong to us.");
57  }
58  }
59 
61  try {
62  return _globalIndexing.dim(index);
63  } catch (Hammer::IndexLabelError&) {
64  throw Hammer::IndexLabelError("Label " + to_string(index) + " not found for multidimensional object of rank " +
65  to_string(rank()) + ": all your base are belong to us.");
66  }
67  }
68 
70  return _globalIndexing.dims();
71  }
72 
74  return _globalIndexing.labels();
75  }
76 
78  return _globalIndexing.spinIndices();
79  }
80 
82  return _globalIndexing.numValues();
83  }
84 
85  bool BlockIndexing::checkValidIndices(const IndexList& indices) const {
86  return _globalIndexing.checkValidIndices(indices);
87  }
88 
89  bool BlockIndexing::checkValidIndices(IndexList::const_iterator first, IndexList::const_iterator last) const {
90  return _globalIndexing.checkValidIndices(first, last);
91  }
92 
93  bool BlockIndexing::checkValidIndices(const vector<IndexList>& splits) const {
94  auto it = _subIndexing.begin();
95  auto its = splits.begin();
96  bool result = true;
97  for(; it != _subIndexing.end() && result; ++it, ++its) {
98  result &= it->checkValidIndices(*its);
99  }
100  return result;
101  }
102 
103  vector<IndexList> BlockIndexing::splitIndices(const IndexList& indices) const {
104  vector<IndexList> result;
105  result.reserve(_subIndexing.size());
106  auto ite= indices.begin();
107  auto itb = ite;
108  for(auto it = _subIndexing.begin(); it != _subIndexing.end(); ++it) {
109  itb = ite;
110  advance(ite, static_cast<ptrdiff_t>(it->rank()));
111  result.emplace_back(IndexList{itb, ite});
112  }
113  return result;
114  }
115 
116  vector<IndexList::const_iterator> BlockIndexing::splitIndices(IndexList::const_iterator first,
117  IndexList::const_iterator last) const {
118  vector<IndexList::const_iterator> result;
119  result.reserve(_subIndexing.size()+1);
120  auto itv = first;
121  for(auto& elem: _subIndexing) {
122  result.push_back(itv);
123  advance(itv, static_cast<ptrdiff_t>(elem.rank()));
124  }
125  result.push_back(last);
126  return result;
127  }
128 
130  bool sortedBySecond) const {
131  return _globalIndexing.getSameLabelPairs(otherLabels, indices, sortedBySecond);
132  }
133 
134  size_t BlockIndexing::maxSubRank() const {
135  size_t result = 0;
136  result = std::accumulate(_subIndexing.begin(), _subIndexing.end(), result, [](size_t current, const LabeledIndexing<AlignedIndexing>& elem) -> size_t { return max(current, elem.rank()); });
137  return result;
138  }
139 
141  return _globalIndexing.getOppositeLabelPairs(indices);
142  }
143 
145  return _globalIndexing.labelIndex(label);
146  }
147 
148  bool BlockIndexing::isSameLabelShape(const LabelsList& otherLabels, const IndexList& otherIndices) const {
149  return _globalIndexing.isSameLabelShape(otherLabels, otherIndices);
150  }
151 
152  bool BlockIndexing::isSameLabelShape(const BlockIndexing& other, bool includeBlockShapes) const {
153  if(includeBlockShapes) {
154  if (_subIndexing.size() != other._subIndexing.size())
155  return false;
156  auto it1 = _subIndexing.begin();
157  auto it2 = other._subIndexing.begin();
158  bool res = true;
159  for (; it1 != _subIndexing.end() && res; ++it1, ++it2) {
160  res &= it1->isSameLabelShape(*it2);
161  }
162  return res;
163  }
164  else {
165  return isSameLabelShape(other.labels(), other.dims());
166  }
167  }
168 
170  IndexType idx = static_cast<IndexType>(distance(_splitIndices.begin(), upper_bound(_splitIndices.begin(),_splitIndices.end(), position)) -1);
171  IndexType res = static_cast<IndexType>(position - _splitIndices[idx]);
172  return make_pair(idx, res);
173  }
174 
176  return _subIndexing[position];
177  }
178 
180  return _subIndexing.size();
181  }
182 
184  LabelsList tmpLabs;
185  IndexList tmpIdxs;
186  _splitIndices.clear();
187  _splitIndices.reserve(_subIndexing.size()+1);
188  _splitIndices.push_back(0);
189  IndexType baseIdx = 0;
190  _splitPads.clear();
191  _splitPads.reserve(_subIndexing.size()+1);
192  _splitPads.push_back(0);
193  IndexList tmpPads;
194  tmpPads.reserve(_subIndexing.size());
195  for(auto& elem: _subIndexing) {
196  tmpLabs.insert(tmpLabs.end(), elem.labels().begin(), elem.labels().end());
197  tmpIdxs.insert(tmpIdxs.end(), elem.dims().begin(), elem.dims().end());
198  baseIdx = static_cast<IndexType>(baseIdx + elem.rank());
199  _splitIndices.push_back(baseIdx);
200  }
201  transform(_subIndexing.rbegin(), _subIndexing.rend(), back_inserter(tmpPads),
202  [](const LabeledIndexing<AlignedIndexing>& val) -> IndexType {
203  return static_cast<IndexType>(minPadding(val.maxIndex()+1));
204  });
205  partial_sum(tmpPads.begin(), tmpPads.end(), back_inserter(_splitPads));
206  _splitPads.pop_back();
207  reverse(_splitPads.begin(), _splitPads.end());
209  }
210 
212  _globalIndexing.flipLabels();
213  for(auto& elem: _subIndexing) {
214  elem.flipLabels();
215  }
216  }
217 
218  vector<tuple<IndexList, vector<bool>, PositionType>> BlockIndexing::processShifts(const DotGroupList& pairs,
219  IndexPairMember which) const {
220  vector<tuple<IndexList, vector<bool>, PositionType>> result;
221  result.reserve(pairs.size() - 1);
222  for(IndexType i=1; i<pairs.size(); ++i) { // first entry is the unassociated;
223  auto tmp = _globalIndexing.processShifts(get<2>(pairs[i]), which);
224  // now process the others: need to eliminate the paddings for the outer indices belonging to
225  // non-contracted subtensors
226  IndexList& shifts = get<0>(tmp);
227  vector<bool>& outerchecks = get<1>(tmp);
228  IndexType maxPad = static_cast<IndexType>(minPadding(get<2>(tmp))); // this is the sum of the pads of all the uncontracted indices (both spectator and non)
229  IndexType currentPadSubtract = 0ul;
230  IndexType previousPad = 0ul;
231  bool recalc = false;
232  const IndexList& used = (which == IndexPairMember::Left) ? get<0>(pairs[i]) : get<1>(pairs[i]);
233  for(IndexType j = static_cast<IndexType>(shifts.size()); j-- > 0;) {
234  if(!outerchecks[j]) continue;
235  auto subPos = getElementIndex(j);
236  bool isUsed = (find(used.begin(), used.end(), subPos.first) != used.end());
237  if(recalc) {
238  currentPadSubtract = static_cast<IndexType>(currentPadSubtract + shifts[j] - previousPad);
239  recalc = false;
240  }
241  if(!isUsed) {
242  previousPad = shifts[j];
243  recalc = true;
244  shifts[j] = maxPad;
245  }
246  else {
247  shifts[j] = static_cast<IndexType>(shifts[j] - currentPadSubtract);
248  }
249  }
250  if(recalc) {
251  currentPadSubtract = static_cast<IndexType>(currentPadSubtract + maxPad - previousPad);
252  }
253  get<2>(tmp) = ((get<2>(tmp)) / (1 << currentPadSubtract)) ; //maxelement for full (i.e 2^(sum of pads of uncontracted indices)) divided by 2^(sum of pads of spectator indices)
254  result.push_back(tmp);
255  }
256  return result;
257  }
258 
260  const IndexList& outerShiftsInnerPositions,
261  const vector<bool>& isOuter, IndexList& innerList,
262  vector<bool>& innerAdded, bool shouldCompare) const {
263  const IndexList& chunkIndices = shouldCompare ? get<1>(chunk) : get<0>(chunk);
264  PositionType fullPos = buildFullPosition(currentPosition, chunkIndices);
265  return _globalIndexing.splitPosition(fullPos, outerShiftsInnerPositions, isOuter, innerList, innerAdded, shouldCompare);
266  }
267 
268 
269  PositionType BlockIndexing::buildFullPosition(const OuterElemIterator& current, const IndexList& chunkIndices) const {
270  PositionType fullPos = 0u;
271  for (IndexType i = 0; i < chunkIndices.size(); ++i) {
272  fullPos += (current.isAligned(i)
273  ? current.position(i)
274  : _subIndexing[chunkIndices[i]].posToAlignedPos(current.position(i)))
275  << _splitPads[chunkIndices[i]];
276  }
277  return fullPos;
278  }
279 
280  OuterElemIterator::OuterElemIterator(const OuterElemIterator& other) : _entry{other._entry}, _containers{other._containers}, _dimensions{other._dimensions} {}
281 
283  : _entry{entry}, _containers(entry.size()), _dimensions(entry.size()) {
284  for (size_t i = 0; i < _entry.size(); ++i) {
285  auto pTry = dynamic_cast<ISingleContainer*>(entry[i].first.get());
286  if (pTry != nullptr) {
287  _containers[i] = pTry;
288  _dimensions[i] = static_cast<IndexType>(pTry->dataSize()/pTry->entrySize());
289 
290  } else {
291  throw Error("Invalid contained type");
292  }
293  }
294  setInitialState();
295  }
296 
298  OuterElemIterator it{*this};
299  it.setInitialState();
300  return it;
301  }
302 
304  OuterElemIterator it{*this};
305  it.setFinalState();
306  return it;
307  }
308 
310  incrementEntry(_it.size(), 1);
311  return *this;
312  }
313 
315  OuterElemIterator it{*this};
316  incrementEntry(_it.size(), n);
317  return it;
318  }
319 
321  IContainer::ElementType result = 1.;
322  for (size_t i = 0; i < _entry.size(); ++i) {
323  result *= _entry[i].second ? conj(_it[i]->value()) : _it[i]->value();
324  }
325  return result;
326  }
327 
329  return _it[idx]->position();
330  }
331 
333  return _it[idx]->isAligned();
334  }
335 
336  bool OuterElemIterator::isSame(const OuterElemIterator& other) const {
337  ASSERT(&_entry == &(other._entry));
338  bool result = true;
339  for (size_t i = 0; i < _it.size() && result; ++i) {
340  result &= (*(_it[i]) == *(other._it[i]));
341  }
342  return result;
343  }
344 
346  _it.resize(_containers.size());
347  for (size_t i = 0; i < _containers.size(); ++i) {
348  _it[i] = _containers[i]->firstNonZero();
349  }
350  }
351 
353  _it.resize(_containers.size());
354  for (size_t i = 0; i < _containers.size(); ++i) {
355  _it[i] = _containers[i]->endNonZero();
356  }
357  }
358 
359  void OuterElemIterator::incrementEntry(size_t position, int n) {
360  if (position == _it.size()) {
361  if (_it[0] == _containers[0]->endNonZero()) {
362  throw RangeError("Invalid increment");
363  }
364  long newpos = static_cast<long>(position) - 1;
365  incrementEntry(static_cast<size_t>(newpos), n);
366  return;
367  }
368  if (position == 0) {
369  if (n + _it[0]->distanceFrom(*_containers[0]->firstNonZero()) >= _dimensions[0]) {
370  for(size_t i = 0; i< _it.size(); ++i) {
371  _it[i] = _containers[i]->endNonZero();
372  }
373  return;
374  }
375  }
376  auto d1 = _it[position]->distanceFrom(*_containers[position]->firstNonZero());
377  auto res = div(d1 + n, static_cast<long>(_dimensions[position]));
378  _it[position]->next(static_cast<int>(res.rem - d1));
379  if (res.quot != 0) {
380  long newpos = static_cast<long>(position) - 1;
381  if (newpos < 0) {
382  for (size_t i = 0; i < _it.size(); ++i) {
383  _it[i] = _containers[i]->endNonZero();
384  }
385  return;
386  }
387  incrementEntry(static_cast<size_t>(newpos), static_cast<int>(res.quot));
388  }
389  return;
390  }
391  } // namespace MultiDimensional
392 
393 } // namespace Hammer
IndexType labelIndex(IndexLabel label) const
std::pair< IndexType, IndexType > IndexPair
bool isSame(const OuterElemIterator &other) const
bool checkValidIndices(const IndexList &indices) const
check that the indices are within range for each component
std::tuple< IndexList, IndexList, IndexPairList > DotGroupType
IndexPairList getSameLabelPairs(const LabelsList &otherLabels, const UniqueLabelsList &indices, bool sortedBySecond=true) const
returns the position of the indices in the two tensor (this and another) that can be contracted toget...
std::vector< IndexList > splitIndices(const IndexList &indices) const
std::vector< IndexPair > IndexPairList
IndexType dim(IndexType index) const
dimension of a specific component
size_t PositionType
#define ASSERT(x)
Definition: Exceptions.hh:95
IndexList dims() const
get the dimensions of all the indices at once
PositionType position(IndexType idx) const
UniqueLabelsList spinIndices() const
returns only the labels corresponding to spin indices
bool isSameLabelShape(const LabelsList &otherLabels, const IndexList &otherIndices) const
void incrementEntry(size_t position, int n)
std::vector< std::pair< SharedTensorData, bool >> EntryType
std::complex< double > ElementType
Definition: IContainer.hh:34
uint16_t IndexType
PositionType splitPosition(const OuterElemIterator &currentPosition, const DotGroupType &chunk, const IndexList &outerShiftsInnerPositions, const std::vector< bool > &isOuter, IndexList &innerList, std::vector< bool > &innerAdded, bool shouldCompare=false) const
PositionType buildFullPosition(const OuterElemIterator &current, const IndexList &chunkIndices) const
Hammer exception definitions.
std::vector< LabeledIndexing< AlignedIndexing > > _subIndexing
std::vector< DotGroupType > DotGroupList
std::vector< IndexType > IndexList
IndexPairList getOppositeLabelPairs(const UniqueLabelsList &indices) const
returns the position of the indices that can be traced together, given a set of allowed index labels ...
Invalid index label error class.
Definition: Exceptions.hh:39
std::vector< PositionType > _splitPads
IndexLabel
label identifiers of tensor indices they are used to determine which indices can be contracted togeth...
Definition: IndexLabels.hh:27
LabeledIndexing< AlignedIndexing > _globalIndexing
Outer product tensor indexer.
std::vector< std::tuple< IndexList, std::vector< bool >, PositionType > > processShifts(const DotGroupList &chunks, IndexPairMember which) const
Generic error class.
Definition: Exceptions.hh:23
std::vector< IndexType > _splitIndices
size_t rank() const
rank of the tensor
const LabeledIndexing< AlignedIndexing > & getSubIndexing(IndexType position) const
std::vector< IndexLabel > LabelsList
PositionType numValues() const
the number of elements (product of all the dimensions)
std::set< IndexLabel > UniqueLabelsList
LabelsList labels() const
get the labels of all the indices at once
std::enable_if< std::is_unsigned< T >::value &&std::is_integral< T >::value, T >::type minPadding(T value)
Definition: Math/Utils.hh:90
Out-of-range error class.
Definition: Exceptions.hh:49
IndexPair getElementIndex(IndexType position) const