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  for(std::size_t i = 0; i < XArrayType::rank::value; i++)
100  {
101  if(fOffsets[i] != 0)
102  {
103  fModuloOffsets[i] = positive_modulo(fOffsets[i], fDimensionSize[i]);
104  }
105  else
106  {
107  fModuloOffsets[i] = 0;
108  }
109  IfTableRotateAxis(in, in, i);
110  }
111 
112  size_t index[XArrayType::rank::value];
113  size_t non_active_dimension_size[XArrayType::rank::value - 1];
114  size_t non_active_dimension_value[XArrayType::rank::value - 1];
115  size_t non_active_dimension_index[XArrayType::rank::value - 1];
116 
117  //select the dimension on which to perform the rotation
118  for(size_t d = 0; d < XArrayType::rank::value; d++)
119  {
120  if(fOffsets[d] != 0)
121  {
122  //now we loop over all dimensions not specified by d
123  //first compute the number of arrays we need to rotate
124  size_t n_rot = 1;
125  size_t count = 0;
126  size_t stride = in->GetStride(d);
127  for(size_t i = 0; i < XArrayType::rank::value; i++)
128  {
129  if(i != d)
130  {
131  n_rot *= fDimensionSize[i];
132  non_active_dimension_index[count] = i;
133  non_active_dimension_size[count] = fDimensionSize[i];
134  count++;
135  }
136  }
137 
138  //loop over the number of rotations to perform
139  for(size_t n = 0; n < n_rot; n++)
140  {
141  //invert place in list to obtain indices of block in array
142  MHO_NDArrayMath::RowMajorIndexFromOffset< XArrayType::rank::value - 1 >(
143  n, non_active_dimension_size, non_active_dimension_value);
144 
145  //copy the value of the non-active dimensions in to index
146  for(size_t i = 0; i < XArrayType::rank::value - 1; i++)
147  {
148  index[non_active_dimension_index[i]] = non_active_dimension_value[i];
149  }
150 
151  //locate the start of this row
152  size_t data_location;
153  index[d] = 0;
154  data_location =
155  MHO_NDArrayMath::OffsetFromRowMajorIndex< XArrayType::rank::value >(fDimensionSize, index);
156 
157  //now rotate the array by the specified amount
158  auto it_first = in->stride_iterator_at(data_location, stride);
159  auto it_nfirst = it_first + fModuloOffsets[d];
160  auto it_end = it_first + fDimensionSize[d];
161  std::rotate(it_first, it_nfirst, it_end);
162  }
163  }
164  }
165  return true;
166  }
167  }
168 
177  virtual bool InitializeOutOfPlace(const XArrayType* in, XArrayType* out) override
178  {
179  if(in != nullptr && out != nullptr)
180  {
181  in->GetDimensions(fDimensionSize);
182  //only need to change output size if in != out and size is different
183  std::size_t in_dim[XArrayType::rank::value];
184  std::size_t out_dim[XArrayType::rank::value];
185  in->GetDimensions(in_dim);
186  out->GetDimensions(out_dim);
187 
188  bool have_to_resize = false;
189  for(std::size_t i = 0; i < XArrayType::rank::value; i++)
190  {
191  if(out_dim[i] != in_dim[i])
192  {
193  have_to_resize = true;
194  break;
195  }
196  }
197 
198  if(have_to_resize)
199  {
200  out->Resize(in_dim);
201  }
202  fInitialized = true;
203  }
204  else
205  {
206  fInitialized = false;
207  }
208  return fInitialized;
209  }
210 
219  virtual bool ExecuteOutOfPlace(const XArrayType* in, XArrayType* out) override
220  {
221  if(fInitialized)
222  {
223  for(std::size_t i = 0; i < XArrayType::rank::value; i++)
224  {
225  if(fOffsets[i] != 0)
226  {
227  fModuloOffsets[i] = positive_modulo(fOffsets[i], fDimensionSize[i]);
228  }
229  IfTableRotateAxis(in, out, i);
230  }
231  //first get the indices of the input iterator
232  auto in_iter = in->cbegin();
233  auto in_iter_end = in->cend();
234  const std::size_t* out_dim = out->GetDimensions();
235  const std::size_t* in_dim = in->GetDimensions();
236  std::array< std::size_t, XArrayType::rank::value > in_loc;
237  while(in_iter != in_iter_end)
238  {
239  MHO_NDArrayMath::RowMajorIndexFromOffset< XArrayType::rank::value >(in_iter.GetOffset(), in_dim,
240  &(in_loc[0]));
241  for(std::size_t i = 0; i < XArrayType::rank::value; i++)
242  {
243  fWorkspace[i] = positive_modulo(in_loc[i] - fModuloOffsets[i], out_dim[i]);
244  }
245  std::size_t out_loc = out->GetOffsetForIndices(fWorkspace);
246  (*(out))[out_loc] = *in_iter;
247  in_iter++;
248  }
249  return true;
250  }
251  return false;
252  }
253 
254  private:
255 
264  template< typename XCheckType = XArrayType >
265  typename std::enable_if< !std::is_base_of< MHO_TableContainerBase, XCheckType >::value, void >::type
266  IfTableRotateAxis(const XArrayType* , XArrayType* , std::size_t ){};
267 
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:244
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:177
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:219
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:121
Class MHO_UnaryOperator.
Definition: MHO_UnaryOperator.hh:24
Definition: MHO_ChannelLabeler.hh:17