Hammer  1.0.0
Helicity Amplitude Module for Matrix Element Reweighting
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Trace.cc
Go to the documentation of this file.
1 ///
2 /// @file Trace.cc
3 /// @brief Tensor trace algorithm
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++ -*-
19 #include "Hammer/Exceptions.hh"
20 #include "Hammer/Tools/Utils.hh"
21 #include "Hammer/Math/Utils.hh"
23 
24 #include <iostream>
25 
26 using namespace std;
27 
28 namespace Hammer {
29 
30  namespace MultiDimensional {
31 
32  using VTensor = VectorContainer;
33  using STensor = SparseContainer;
34  using OTensor = OuterContainer;
35  using Base = IContainer;
36 
37  namespace Ops {
38 
39  Trace::Trace(const IndexPairList& indices) : _indices{indices} {
40  _idxSet.clear();
41  for (auto& elem : _indices) {
42  _idxSet.insert(elem.first);
43  _idxSet.insert(elem.second);
44  }
45  }
46 
48  auto newdimlabs = getNewIndexLabels(a);
49  auto strides = a.getIndexing().processShifts(_indices, IndexPairMember::Both);
50  IndexList inners(a.dims().size() - newdimlabs.first.size());
51  vector<bool> innerAdds(inners.size(), false);
52  if (newdimlabs.first.size() > 0) {
53  auto newsparse = makeEmptySparse(newdimlabs.first, newdimlabs.second);
54  STensor* result = static_cast<STensor*>(newsparse.release());
55  for (auto& elem : a) {
56  auto pospairs = a.getIndexing().splitPosition(elem.first, get<0>(strides), get<1>(strides), inners, innerAdds);
57  if (pospairs == numeric_limits<size_t>::max())
58  continue;
59  (*result)[pospairs] += elem.second;
60  }
61  return static_cast<Base*>(result);
62  } else {
63  auto newscalar = makeEmptyScalar();
64  IContainer::ElementType res = 0.;
65  for (auto& elem : a) {
66  auto pospairs =
67  a.getIndexing().splitPosition(elem.first, get<0>(strides), get<1>(strides), inners, innerAdds);
68  if (pospairs == numeric_limits<size_t>::max())
69  continue;
70  res += elem.second;
71  }
72  newscalar->element({}) = res;
73  return newscalar.release();
74  }
75  }
76 
78  auto newdimlabs = getNewIndexLabels(a);
79  auto strides = a.getIndexing().getInnerOuterStrides(_indices, a.getIndexing().strides(), true);
80  if (newdimlabs.first.size() > 0) {
81  auto newvect = makeEmptyVector(newdimlabs.first, newdimlabs.second);
82  VTensor* result = static_cast<VTensor*>(newvect.release());
83  for (size_t i = 0; i < a.numValues(); ++i) {
84  if (isZero(a[i])) {
85  continue;
86  }
87  auto pospairs = a.getIndexing().splitPosition(i, strides);
88  if (pospairs.second == 0) {
89  (*result)[pospairs.first] += a[i];
90  }
91  }
92  return static_cast<Base*>(result);
93  }
94  else {
95  auto newscalar = makeEmptyScalar();
96  IContainer::ElementType res = 0.;
97  for (size_t i = 0; i < a.numValues(); ++i) {
98  if (isZero(a[i])) {
99  continue;
100  }
101  auto pospairs = a.getIndexing().splitPosition(i, strides);
102  if (pospairs.second == 0) {
103  res += a[i];
104  }
105  }
106  newscalar->element({}) = res;
107  return newscalar.release();
108  }
109  }
110 
111 
113  // assume no traces of subtensors
114  for(auto& elem: _indices) {
115  UNUSED(elem.first);
116  ASSERT(a.getIndexing().getElementIndex(elem.first).first != a.getIndexing().getElementIndex(elem.second).first);
117  }
118  if(a.getIndexing().numSubIndexing() == 2) {
119  // specialize for the standard outersquare case:
120  // just one dot and not an outer anymore
121  IndexPairList contraction;
122  contraction.reserve(_indices.size());
123  IndexType divider = static_cast<IndexType>(a.getIndexing().getSubIndexing(0).rank());
124  for(auto& elem: _indices) {
125  if(elem.first < elem.second) {
126  contraction.push_back({elem.first, elem.second - divider});
127  }
128  else {
129  contraction.push_back({elem.second, elem.first - divider});
130  }
131  }
132  auto newdimlabs = getNewIndexLabels(a);
133  // Outer is going to be collapsed
134  TensorData result;
135  if (newdimlabs.first.size() == 0) {
136  result = makeEmptyScalar();
137  } else {
138  result = makeEmptySparse(newdimlabs.first, newdimlabs.second);
139  }
140  SharedTensorData current_entry;
141  Ops::Sum summer{};
142  for (auto& elem : a) {
143  Ops::Dot dotter{contraction, {elem[0].second, elem[1].second}};
144  current_entry = calc2(elem[0].first, *elem[1].first, dotter, "dot_outertrace");
145  if(result->rank() == 0) {
146  result->element({}) += current_entry->element({});
147  }
148  else {
149  result = calc2(move(result), *current_entry, summer, "sum_outertrace");
150  }
151  }
152  return result.release();
153  }
154  else {
155  /// @todo IMPLEMENT
156  throw Error("Unimplemented tr O for general case");
157  // // everything's a dot find which ones
158  // map<IndexPair, IndexPairList, greater<IndexPair>> contractions;
159  // for (auto& elem : _indices) {
160  // auto tmpLeft = a.getIndexing().getElementIndex(elem.first);
161  // auto tmpRight = a.getIndexing().getElementIndex(elem.second);
162  // if (tmpLeft.first > tmpRight.first) {
163  // contractions[{tmpLeft.first, tmpRight.first}].push_back(
164  // {tmpLeft.second, tmpRight.second});
165  // } else {
166  // contractions[{tmpRight.first, tmpLeft.first}].push_back(
167  // {tmpRight.second, tmpLeft.second});
168  // }
169  // }
170  // // be lazy: do one set of contractions and then call trace again
171  // auto it = contractions.begin();
172  // for (auto& elem : a) {
173  // Ops::Dot dotter{it->second, {elem.second[it->first.second], elem.second[it->first.first]}};
174  // elem.first[it->first.first] = calc2(elem.first[it->first.second],
175  // *elem.first[it->first.first], dotter, "dot_outertrace");
176  // elem.second[it->first.first] = false;
177  // elem.first.erase(elem.first.begin() + it->first.second);
178  // elem.second.erase(elem.second.begin() + it->first.second);
179  // }
180  // // now fix indexing before recursively calling trace
181  }
182  }
183 
184  Base* Trace::error(Base&) {
185  throw Error("Invalid data types for tensor Trace");
186  }
187 
188  std::pair<IndexList, LabelsList> Trace::getNewIndexLabels(const IContainer& original) const {
189  IndexList resultD = original.dims();
190  LabelsList resultL = original.labels();
191  for (auto elem : reverse_range(_idxSet)) {
192  resultD.erase(resultD.begin() + elem);
193  resultL.erase(resultL.begin() + elem);
194  }
195  return make_pair(resultD, resultL);
196  }
197 
198  IndexList Trace::reducedIndex(const IndexList& a) const {
199  IndexList result = a;
200  for (auto elem : reverse_range(_idxSet)) {
201  result.erase(result.begin() + elem);
202  }
203  return result;
204  }
205 
206  } // namespace Ops
207 
208 
209  } // namespace MultiDimensional
210 
211 } // namespace Hammer
TensorData makeEmptySparse(const IndexList &dimensions, const LabelsList &labels)
const LabeledIndexing< SequentialIndexing > & getIndexing() const
const LabeledIndexing< AlignedIndexing > & getIndexing() const
virtual LabelsList labels() const =0
std::vector< IndexPair > IndexPairList
reversion_wrapper< T > reverse_range(T &&iterable)
Definition: Tools/Utils.hh:89
#define ASSERT(x)
Definition: Exceptions.hh:95
Non-sparse tensor data container.
std::complex< double > ElementType
Definition: IContainer.hh:34
uint16_t IndexType
IContainer * operator()(VectorContainer &first)
Definition: Trace.cc:77
Tensor sum algorithm.
TensorPtr calc2(TensorPtr origin, const IContainer &other, Ops op, std::string opName)
std::unique_ptr< IContainer > TensorData
std::shared_ptr< IContainer > SharedTensorData
Tensor operations helper functions.
(Sum of) Outer product tensor data container
Hammer exception definitions.
Tensor trace algorithm.
Sparse tensor data container.
std::vector< IndexType > IndexList
#define UNUSED(x)
Definition: Tools/Utils.hh:28
Order-0 tensor data container.
virtual IndexList dims() const =0
Generic error class.
Definition: Exceptions.hh:23
bool isZero(const std::complex< double > val)
Definition: Math/Utils.hh:25
SparseContainer STensor
Definition: AddAt.cc:28
const BlockIndexing & getIndexing() const
reference element(const IndexList &coords={}) override
const LabeledIndexing< AlignedIndexing > & getSubIndexing(IndexType position) const
std::vector< IndexLabel > LabelsList
VectorContainer VTensor
Definition: AddAt.cc:27
TensorData makeEmptyVector(const IndexList &dimensions, const LabelsList &labels)
OuterContainer OTensor
Definition: AddAt.cc:29
Tensor dot product algorithm.
IndexPair getElementIndex(IndexType position) const
std::pair< IndexList, LabelsList > getNewIndexLabels(const IContainer &original) const
Definition: Trace.cc:188