HOPS
HOPS class reference
MHO_CyclicRotator.hh
Go to the documentation of this file.
1 #ifndef MHO_CyclicRotator_HH__
2 #define MHO_CyclicRotator_HH__
3 
4 #include <algorithm>
5 #include <cstdint>
6 
7 #include "MHO_Message.hh"
8 #include "MHO_NDArrayWrapper.hh"
9 #include "MHO_TableContainer.hh"
10 #include "MHO_UnaryOperator.hh"
11 
12 namespace hops
13 {
14 
28 template< class XArrayType > class MHO_CyclicRotator: public MHO_UnaryOperator< XArrayType >
29 {
30  public:
32  {
33  fInitialized = false;
34  for(std::size_t i = 0; i < XArrayType::rank::value; i++)
35  {
36  fDimensionSize[i] = 0;
37  fOffsets[i] = 0;
38  }
39  };
40 
41  virtual ~MHO_CyclicRotator(){};
42 
52  void SetOffset(std::size_t dimension_index, int64_t offset_value)
53  {
54  if(dimension_index < XArrayType::rank::value)
55  {
56  fOffsets[dimension_index] = offset_value;
57  }
58  else
59  {
60  msg_error("operators",
61  "error, rotation offset for dimension: " << dimension_index << ", exceeds array rank." << eom);
62  }
63  fInitialized = false;
64  }
65 
66  protected:
74  virtual bool InitializeInPlace(XArrayType* in) override
75  {
76  if(in != nullptr)
77  {
78  in->GetDimensions(fDimensionSize);
79  fInitialized = true;
80  }
81  return fInitialized;
82  }
83 
91  virtual bool ExecuteInPlace(XArrayType* in) override
92  {
93  if(!fInitialized)
94  {
95  return false;
96  }
97  else
98  {
99  //profiler_scope();
100  for(std::size_t i = 0; i < XArrayType::rank::value; i++)
101  {
102  if(fOffsets[i] != 0)
103  {
104  fModuloOffsets[i] = positive_modulo(fOffsets[i], fDimensionSize[i]);
105  }
106  else
107  {
108  fModuloOffsets[i] = 0;
109  }
110  IfTableRotateAxis(in, in, i);
111  }
112 
113  size_t index[XArrayType::rank::value];
114  size_t non_active_dimension_size[XArrayType::rank::value - 1];
115  size_t non_active_dimension_value[XArrayType::rank::value - 1];
116  size_t non_active_dimension_index[XArrayType::rank::value - 1];
117 
118  //select the dimension on which to perform the rotation
119  for(size_t d = 0; d < XArrayType::rank::value; d++)
120  {
121  if(fOffsets[d] != 0)
122  {
123  //now we loop over all dimensions not specified by d
124  //first compute the number of arrays we need to rotate
125  size_t n_rot = 1;
126  size_t count = 0;
127  size_t stride = in->GetStride(d);
128  for(size_t i = 0; i < XArrayType::rank::value; i++)
129  {
130  if(i != d)
131  {
132  n_rot *= fDimensionSize[i];
133  non_active_dimension_index[count] = i;
134  non_active_dimension_size[count] = fDimensionSize[i];
135  count++;
136  }
137  }
138 
139  //loop over the number of rotations to perform
140  for(size_t n = 0; n < n_rot; n++)
141  {
142  //invert place in list to obtain indices of block in array
143  MHO_NDArrayMath::RowMajorIndexFromOffset< XArrayType::rank::value - 1 >(
144  n, non_active_dimension_size, non_active_dimension_value);
145 
146  //copy the value of the non-active dimensions in to index
147  for(size_t i = 0; i < XArrayType::rank::value - 1; i++)
148  {
149  index[non_active_dimension_index[i]] = non_active_dimension_value[i];
150  }
151 
152  //locate the start of this row
153  size_t data_location;
154  index[d] = 0;
155  data_location =
156  MHO_NDArrayMath::OffsetFromRowMajorIndex< XArrayType::rank::value >(fDimensionSize, index);
157 
158  //now rotate the array by the specified amount
159  auto it_first = in->stride_iterator_at(data_location, stride);
160  auto it_nfirst = it_first + fModuloOffsets[d];
161  auto it_end = it_first + fDimensionSize[d];
162  std::rotate(it_first, it_nfirst, it_end);
163  }
164  }
165  }
166  return true;
167  }
168  }
169 
178  virtual bool InitializeOutOfPlace(const XArrayType* in, XArrayType* out) override
179  {
180  if(in != nullptr && out != nullptr)
181  {
182  in->GetDimensions(fDimensionSize);
183  //only need to change output size if in != out and size is different
184  std::size_t in_dim[XArrayType::rank::value];
185  std::size_t out_dim[XArrayType::rank::value];
186  in->GetDimensions(in_dim);
187  out->GetDimensions(out_dim);
188 
189  bool have_to_resize = false;
190  for(std::size_t i = 0; i < XArrayType::rank::value; i++)
191  {
192  if(out_dim[i] != in_dim[i])
193  {
194  have_to_resize = true;
195  break;
196  }
197  }
198 
199  if(have_to_resize)
200  {
201  out->Resize(in_dim);
202  }
203  fInitialized = true;
204  }
205  else
206  {
207  fInitialized = false;
208  }
209  return fInitialized;
210  }
211 
220  virtual bool ExecuteOutOfPlace(const XArrayType* in, XArrayType* out) override
221  {
222  if(fInitialized)
223  {
224  //profiler_scope();
225  for(std::size_t i = 0; i < XArrayType::rank::value; i++)
226  {
227  if(fOffsets[i] != 0)
228  {
229  fModuloOffsets[i] = positive_modulo(fOffsets[i], fDimensionSize[i]);
230  }
231  IfTableRotateAxis(in, out, i);
232  }
233  //first get the indices of the input iterator
234  auto in_iter = in->cbegin();
235  auto in_iter_end = in->cend();
236  const std::size_t* out_dim = out->GetDimensions();
237  const std::size_t* in_dim = in->GetDimensions();
238  std::array< std::size_t, XArrayType::rank::value > in_loc;
239  while(in_iter != in_iter_end)
240  {
241  MHO_NDArrayMath::RowMajorIndexFromOffset< XArrayType::rank::value >(in_iter.GetOffset(), in_dim,
242  &(in_loc[0]));
243  for(std::size_t i = 0; i < XArrayType::rank::value; i++)
244  {
245  fWorkspace[i] = positive_modulo(in_loc[i] - fModuloOffsets[i], out_dim[i]);
246  }
247  std::size_t out_loc = out->GetOffsetForIndices(fWorkspace);
248  (*(out))[out_loc] = *in_iter;
249  in_iter++;
250  }
251  return true;
252  }
253  return false;
254  }
255 
256  private:
265  template< typename XCheckType = XArrayType >
266  typename std::enable_if< !std::is_base_of< MHO_TableContainerBase, XCheckType >::value, void >::type
267  IfTableRotateAxis(const XArrayType* , XArrayType* , std::size_t ){};
268 
278  template< typename XCheckType = XArrayType >
279  typename std::enable_if< std::is_base_of< MHO_TableContainerBase, XCheckType >::value, void >::type
280  IfTableRotateAxis(const XArrayType* in, XArrayType* out, std::size_t dim)
281  {
282  RotateAxis axis_rot(fOffsets[dim]);
283  apply_at2< typename XArrayType::axis_pack_tuple_type, RotateAxis >(*in, *out, dim, axis_rot);
284  }
285 
289  class RotateAxis
290  {
291  public:
292  RotateAxis(std::size_t offset): fOffset(offset){};
293  ~RotateAxis(){};
294 
295  template< typename XAxisType > void operator()(const XAxisType& axis1, XAxisType& axis2)
296  {
297  if(fOffset != 0)
298  {
299  XAxisType tmp;
300  tmp.Copy(axis1);
301  axis2.Copy(axis1); //copy the axis first to get tags, etc.
302  //now rotate the elements by the offset
303  std::size_t a, b;
304  int64_t i, j;
305  int64_t n = axis2.GetSize();
306  for(i = 0; i < n; i++)
307  {
308  j = ((i - fOffset) % n + n) % n;
309  a = i;
310  b = j;
311  axis2(a) = tmp(b);
312  }
313  }
314  else
315  {
316  axis2.Copy(axis1);
317  }
318  }
319 
320  private:
321  int64_t fOffset;
322  };
323 
324  //note: using the modulo is a painfully slow to do this
325  //TODO FIXME...we ought to check for uint64_t -> int64_t overflows!
333  inline int64_t positive_modulo(int64_t i, int64_t n) { return (i % n + n) % n; }
334 
335  //offsets to for cyclic rotation
336  bool fInitialized;
337  std::size_t fDimensionSize[XArrayType::rank::value];
338  int64_t fOffsets[XArrayType::rank::value];
339  int64_t fModuloOffsets[XArrayType::rank::value];
340  std::size_t fWorkspace[XArrayType::rank::value];
341 };
342 
343 }; // namespace hops
344 
345 #endif
#define msg_error(xKEY, xCONTENT)
Definition: MHO_Message.hh:238
Class MHO_CyclicRotator.
Definition: MHO_CyclicRotator.hh:29
void SetOffset(std::size_t dimension_index, int64_t offset_value)
set the offset for the cyclic rotation in each dimension (default is zero...do nothing)
Definition: MHO_CyclicRotator.hh:52
virtual ~MHO_CyclicRotator()
Definition: MHO_CyclicRotator.hh:41
virtual bool InitializeOutOfPlace(const XArrayType *in, XArrayType *out) override
Function InitializeOutOfPlace - executes the rotation.
Definition: MHO_CyclicRotator.hh:178
MHO_CyclicRotator()
Definition: MHO_CyclicRotator.hh:31
virtual bool InitializeInPlace(XArrayType *in) override
Initializes in-place rotation and sets flag if input is not nullptr.
Definition: MHO_CyclicRotator.hh:74
virtual bool ExecuteOutOfPlace(const XArrayType *in, XArrayType *out) override
Function ExecuteOutOfPlace - executes the rotation.
Definition: MHO_CyclicRotator.hh:220
virtual bool ExecuteInPlace(XArrayType *in) override
Function ExecuteInPlace - executes the rotation.
Definition: MHO_CyclicRotator.hh:91
static void RowMajorIndexFromOffset(std::size_t offset, const std::size_t *DimSize, std::size_t *Index)
Function RowMajorIndexFromOffset.
Definition: MHO_NDArrayMath.hh:117
Class MHO_UnaryOperator.
Definition: MHO_UnaryOperator.hh:24
Definition: MHO_AdhocFlagging.hh:18