Interface Documentation
Version: invalid
filling_curve.hh
Go to the documentation of this file.
1 /*
2  @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@
3  /@@///// /@@ @@////@@ @@////// /@@
4  /@@ /@@ @@@@@ @@ // /@@ /@@
5  /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@
6  /@@//// /@@/@@@@@@@/@@ ////////@@/@@
7  /@@ /@@/@@//// //@@ @@ /@@/@@
8  /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@
9  // /// ////// ////// //////// //
10 
11  Copyright (c) 2016, Los Alamos National Security, LLC
12  All rights reserved.
13  */
14 #pragma once
15 
18 
19 //----------------------------------------------------------------------------//
22 //----------------------------------------------------------------------------//
23 
24 namespace flecsi {
25 
26 /*----------------------------------------------------------------------------*
27  * class filling_curve
28  * @brief Basic functionality for a space filling curve.
29  * The filling_curves are built using a CRTP pattern.
30  * This base class features the generic function to generate filling curves
31  * and is specialized but \ref hilbert_curve and \ref morton_curve
32  *----------------------------------------------------------------------------*/
33 template<size_t DIM, typename T, class DERIVED>
35 {
36  static constexpr size_t dimension = DIM;
37  using int_t = T;
39  using range_t = std::array<point_t, 2>;
40 
41 protected:
42  static constexpr size_t bits_ = sizeof(int_t) * 8;
43  static constexpr size_t max_depth_ =
44  (bits_ - 1) /
45  dimension;
46  static constexpr size_t max_value_ = int_t(1) << (max_depth_ - 1);
48 
49  static double min_, scale_;
50  static range_t range_;
51  int_t value_;
52  filling_curve(int_t value) : value_(value) {}
53 
54 public:
55  filling_curve() : value_(0) {}
56 
57  static size_t max_depth() {
58  return max_depth_;
59  }
60 
62  static constexpr DERIVED min() {
63  return DERIVED(int_t(1) << max_depth_ * dimension);
64  }
66  static constexpr DERIVED max() {
67  int_t id = ~static_cast<int_t>(0);
68  for(size_t i = max_depth_ * dimension + 1; i < bits_; ++i) {
69  id ^= int_t(1) << i;
70  } // for
71  return DERIVED(id);
72  }
74  static constexpr DERIVED root() {
75  return DERIVED(int_t(1));
76  }
78  static constexpr DERIVED null() {
79  return DERIVED(0);
80  }
82  constexpr bool is_null() const {
83  return value_ == int_t(0);
84  }
86  size_t depth() const {
87  int_t id = value_;
88  size_t d = 0;
89  while(id >>= dimension)
90  ++d;
91  return d;
92  }
94  void push(int_t bits) {
95  assert(bits < int_t(1) << dimension);
96  value_ <<= dimension;
97  value_ |= bits;
98  }
100  void pop() {
101  assert(depth() > 0);
102  value_ >>= dimension;
103  }
104 
107  int conflict = max_depth_;
108  while(key_a != key_b) {
109  key_a.pop();
110  key_b.pop();
111  --conflict;
112  } // while
113  return conflict;
114  }
116  int pop_value() {
117  assert(depth() > 0);
118  int poped = 0;
119  poped = value_ & ((1 << (dimension)) - 1);
120  assert(poped < (1 << dimension));
121  value_ >>= dimension;
122  return poped;
123  }
125  int last_value() {
126  int poped = 0;
127  poped = value_ & ((1 << (dimension)) - 1);
128  return poped;
129  }
131  void pop(size_t d) {
132  assert(d >= depth());
133  value_ >>= d * dimension;
134  }
135 
137  constexpr filling_curve parent() const {
138  return DERIVED(value_ >> dimension);
139  }
140 
142  void truncate(size_t to_depth) {
143  size_t d = depth();
144  if(d < to_depth) {
145  return;
146  }
147  value_ >>= (d - to_depth) * dimension;
148  }
150  void output_(std::ostream & ostr) const {
151  if constexpr(dimension == 3) {
152  ostr << std::oct << value_ << std::dec;
153  }
154  else {
155  std::string output;
156  filling_curve id = *this;
157  int poped;
158  while(id != root()) {
159  poped = id.pop_value();
160  output.insert(0, std::to_string(poped));
161  } // while
162  output.insert(output.begin(), '1');
163  ostr << output.c_str();
164  } // if else
165  }
167  int_t value() const {
168  return value_;
169  }
171  virtual void coordinates(point_t &) {}
172 
173  constexpr bool operator==(const filling_curve & bid) const {
174  return value_ == bid.value_;
175  }
176 
177  constexpr bool operator<=(const filling_curve & bid) const {
178  return value_ <= bid.value_;
179  }
180 
181  constexpr bool operator>=(const filling_curve & bid) const {
182  return value_ >= bid.value_;
183  }
184 
185  constexpr bool operator>(const filling_curve & bid) const {
186  return value_ > bid.value_;
187  }
188 
189  constexpr bool operator<(const filling_curve & bid) const {
190  return value_ < bid.value_;
191  }
192 
193  constexpr bool operator!=(const filling_curve & bid) const {
194  return value_ != bid.value_;
195  }
196 
197  operator int_t() const {
198  return value_;
199  }
200 
201 }; // class filling_curve
202 
204 template<size_t D, typename T, class DER>
205 std::ostream &
206 operator<<(std::ostream & ostr, const filling_curve<D, T, DER> & k) {
207  k.output_(ostr);
208  return ostr;
209 }
210 
211 /*----------------------------------------------------------------------------*
212  * class hilbert_curve
213  * @brief Implementation of the hilbert peano space filling curve in
214  * 1, 2 and 3d
215  *----------------------------------------------------------------------------*/
216 template<size_t DIM, typename T>
217 class hilbert_curve : public filling_curve<DIM, T, hilbert_curve<DIM, T>>
218 {
219  using int_t = T;
220  static constexpr size_t dimension = DIM;
221  using coord_t = std::array<int_t, dimension>;
223  using range_t = std::array<point_t, 2>;
224 
228 
232 
233 public:
235  hilbert_curve(const int_t & id) : filling_curve<DIM, T, hilbert_curve>(id) {}
236  hilbert_curve(const hilbert_curve & bid)
237  : filling_curve<DIM, T, hilbert_curve>(bid.value_) {}
238  hilbert_curve(const point_t & p)
240 
243  hilbert_curve(const point_t & p, const size_t depth) {
245  assert(depth <= max_depth_);
246  std::array<int_t, dimension> coords;
247  // Convert the position to integer
248  for(std::size_t i = 0; i < dimension; ++i) {
249  coords[i] = (p[i] - min_) / scale_ * max_value_;
250  }
251  // Handle 1D case
252  if constexpr(dimension == 1) {
253  assert(value_ & 1UL << max_depth_);
254  value_ |= coords[0] >> dimension;
255  value_ >>= (max_depth_ - depth);
256  return;
257  }
258  int shift = max_depth_ - 1;
259  for(int_t mask = max_value_ >> 1; mask > 0; mask >>= 1, --shift) {
260  std::array<bool, dimension> r;
261  if constexpr(dimension == 2) {
262  r = {!!(mask & coords[0]), !!(mask & coords[1])};
263  int_t bits = ((3 * r[0]) ^ r[1]);
264  value_ |= bits << (shift * 2);
265  rotation2d(mask, coords, r);
266  }
267  if constexpr(dimension == 3) {
268  r = {!!(mask & coords[0]), !!(mask & coords[1]), !!(mask & coords[2])};
269  int_t bits = (7 * r[0]) ^ (3 * r[1]) ^ r[2];
270  value_ |= bits << (shift * 3);
271  unrotation3d(mask, coords, r);
272  }
273  }
274  assert(value_ & int_t(1) << (max_depth_ * dimension));
275  // Then truncate the key to the depth
276  value_ >>= (max_depth_ - depth) * dimension;
277  }
278 
279  static void set_range(const range_t & range) {
280  range_ = range;
281  for(std::size_t i = 0; i < dimension; ++i) {
282  min_ = range_[0][i];
283  scale_ = range_[1][i] - min_;
284  }
285  }
286 
288  void coordinates(point_t & p) {
289  int_t key = value_;
290  std::array<int_t, dimension> coords = {};
291  for(int_t mask = int_t(1); mask <= max_value_; mask <<= 1) {
292  std::array<bool, dimension> r = {};
293  if constexpr(dimension == 3) {
294  r[0] = (!!(key & 4));
295  r[1] = (!!(key & 2)) ^ r[0];
296  r[2] = (!!(key & 1)) ^ r[0] ^ r[1];
297  rotation3d(mask, coords, r);
298  coords[0] += r[0] * mask;
299  coords[1] += r[1] * mask;
300  coords[2] += r[2] * mask;
301  }
302  if constexpr(dimension == 2) {
303  r[0] = (!!(key & 2));
304  r[1] = (!!(key & 1)) ^ r[0];
305  // r[0] = r[0] ^ r[1];
306  rotation2d(mask, coords, r);
307  coords[0] += r[0] * mask;
308  coords[1] += r[1] * mask;
309  }
310  key >>= dimension;
311  }
312 
313  assert(key == int_t(1));
314  for(std::size_t j = 0; j < dimension; ++j) {
315  p[j] = min_ + scale_ * static_cast<double>(coords[j]) / max_value_ / 2;
316  } // for
317  }
318 
319  hilbert_curve & operator=(const hilbert_curve & bid) {
320  value_ = bid.value_;
321  return *this;
322  }
323 
324 private:
325  void rotation2d(const int_t & n,
326  std::array<int_t, dimension> & coords,
327  const std::array<bool, dimension> & bits) {
328  if(bits[1] == 0) {
329  if(bits[0] == 1) {
330  coords[0] = n - 1 - coords[0];
331  coords[1] = n - 1 - coords[1];
332  }
333  // Swap X-Y or Z
334  std::swap(coords[0], coords[1]);
335  }
336  }
337 
338  void rotate_90_x(const int_t & n, coord_t & coords) {
339  coord_t tmp = coords;
340  coords = {tmp[0], n - tmp[2] - 1, tmp[1]};
341  }
342  void rotate_90_y(const int_t & n, coord_t & coords) {
343  coord_t tmp = coords;
344  coords = {tmp[2], tmp[1], n - tmp[0] - 1};
345  }
346  void rotate_90_z(const int_t & n, coord_t & coords) {
347  coord_t tmp = coords;
348  coords = {n - tmp[1] - 1, tmp[0], tmp[2]};
349  }
350  void rotate_180_x(const int_t & n, coord_t & coords) {
351  coord_t tmp = coords;
352  coords = {tmp[0], n - tmp[1] - 1, n - tmp[2] - 1};
353  }
354  void rotate_270_x(const int_t & n, coord_t & coords) {
355  coord_t tmp = coords;
356  coords = {tmp[0], tmp[2], n - tmp[1] - 1};
357  }
358  void rotate_270_y(const int_t & n, coord_t & coords) {
359  coord_t tmp = coords;
360  coords = {n - tmp[2] - 1, tmp[1], tmp[0]};
361  }
362  void rotate_270_z(const int_t & n, coord_t & coords) {
363  coord_t tmp = coords;
364  coords = {tmp[1], n - tmp[0] - 1, tmp[2]};
365  }
366 
367  void rotation3d(const int_t & n,
368  coord_t & coords,
369  const std::array<bool, dimension> & r) {
370  if(!r[0] && !r[1] && !r[2]) {
371  // Left front bottom
372  rotate_270_z(n, coords);
373  rotate_270_x(n, coords);
374  }
375  else if(!r[0] && r[2]) {
376  // Left top
377  rotate_90_z(n, coords);
378  rotate_90_y(n, coords);
379  }
380  else if(r[1] && !r[2]) {
381  // Back bottom
382  rotate_180_x(n, coords);
383  }
384  else if(r[0] && r[2]) {
385  // Right top
386  rotate_270_z(n, coords);
387  rotate_270_y(n, coords);
388  }
389  else if(r[0] && !r[2] && !r[1]) {
390  // Right front bottom
391  rotate_90_y(n, coords);
392  rotate_90_z(n, coords);
393  }
394  }
395 
396  void unrotation3d(const int_t & n,
397  coord_t & coords,
398  const std::array<bool, dimension> & r) {
399  if(!r[0] && !r[1] && !r[2]) {
400  // Left front bottom
401  rotate_90_x(n, coords);
402  rotate_90_z(n, coords);
403  }
404  else if(!r[0] && r[2]) {
405  // Left top
406  rotate_270_y(n, coords);
407  rotate_270_z(n, coords);
408  }
409  else if(r[1] && !r[2]) {
410  // Back bottom
411  rotate_180_x(n, coords);
412  }
413  else if(r[0] && r[2]) {
414  // Right top
415  rotate_90_y(n, coords);
416  rotate_90_z(n, coords);
417  }
418  else if(r[0] && !r[2] && !r[1]) {
419  // Right front bottom
420  rotate_270_z(n, coords);
421  rotate_270_y(n, coords);
422  }
423  }
424 }; // class hilbert
425 
426 /*----------------------------------------------------------------------------*
427  * class morton_curve
428  * @brief Implementation of the Morton space filling curve (Z ordering)
429  *----------------------------------------------------------------------------*/
430 template<size_t DIM, typename T>
431 class morton_curve : public filling_curve<DIM, T, morton_curve<DIM, T>>
432 {
433 
434  using int_t = T;
435  static constexpr size_t dimension = DIM;
436  using coord_t = std::array<int_t, dimension>;
438  using range_t = std::array<point_t, 2>;
439 
443 
448 
449 public:
451  morton_curve(const int_t & id) : filling_curve<DIM, T, morton_curve>(id) {}
452  morton_curve(const morton_curve & bid)
453  : filling_curve<DIM, T, morton_curve>(bid.value_) {}
454  morton_curve(const point_t & p)
456 
458  morton_curve(const point_t & p, const size_t depth) {
460  assert(depth <= max_depth_);
461  std::array<int_t, dimension> coords;
462  for(size_t i = 0; i < dimension; ++i) {
463  coords[i] =
464  (p[i] - min_) / scale_ * (int_t(1) << (bits_ - 1) / dimension);
465  }
466  size_t k = 0;
467  for(size_t i = max_depth_ - depth; i < max_depth_; ++i) {
468  for(size_t j = 0; j < dimension; ++j) {
469  int_t bit = (coords[j] & int_t(1) << i) >> i;
470  value_ |= bit << (k * dimension + j);
471  } // for
472  ++k;
473  } // for
474  } // morton_curve
475 
476  static void set_range(const range_t & range) {
477  range_ = range;
478  for(std::size_t i = 0; i < dimension; ++i) {
479  min_ = range_[0][i];
480  scale_ = range_[1][i] - min_;
481  }
482  }
483 
485  void coordinates(point_t & p) {
486  std::array<int_t, dimension> coords;
487  coords.fill(int_t(0));
488  int_t id = value_;
489  size_t d = 0;
490  while(id >> dimension != int_t(0)) {
491  for(size_t j = 0; j < dimension; ++j) {
492  coords[j] |= (((int_t(1) << j) & id) >> j) << d;
493  } // for
494  id >>= dimension;
495  ++d;
496  } // while
497  constexpr int_t m = (int_t(1) << max_depth_) - 1;
498  for(size_t j = 0; j < dimension; ++j) {
499  coords[j] <<= max_depth_ - d;
500  p[j] = min_ + scale_ * static_cast<double>(coords[j]) / m;
501  } // for
502  } // coordinates
503 
504  morton_curve & operator=(const morton_curve & bid) {
505  value_ = bid.value_;
506  return *this;
507  }
508 
509 }; // class morton
510 
511 template<size_t DIM, typename T, class DERIVED>
513 template<size_t DIM, typename T, class DERIVED>
514 typename filling_curve<DIM, T, DERIVED>::range_t
516 template<size_t DIM, typename T, class DERIVED>
518 
519 } // namespace flecsi
int pop_value()
Pop and return the digit popped.
Definition: filling_curve.hh:116
Definition: filling_curve.hh:217
int last_value()
Return the last digit of the key.
Definition: filling_curve.hh:125
void pop(size_t d)
Pop the depth d bits from the end of this key.
Definition: filling_curve.hh:131
static constexpr size_t max_depth_
Maximum number of bits.
Definition: filling_curve.hh:43
static constexpr DERIVED max()
Biggest value possible at max_depth considering the root.
Definition: filling_curve.hh:66
constexpr bool is_null() const
Definition: filling_curve.hh:82
hilbert_curve(const point_t &p, const size_t depth)
Definition: filling_curve.hh:243
void truncate(size_t to_depth)
Truncate this key until it is of depth to_depth.
Definition: filling_curve.hh:142
static constexpr DERIVED min()
Smallest value possible at max_depth considering the root.
Definition: filling_curve.hh:62
Definition: filling_curve.hh:431
void pop()
Definition: filling_curve.hh:100
static constexpr size_t max_value_
Definition: filling_curve.hh:47
morton_curve(const point_t &p, const size_t depth)
Morton key can be generated directly up to the right depth.
Definition: filling_curve.hh:458
static constexpr DERIVED null()
Definition: filling_curve.hh:78
Definition: dimensioned_array.hh:58
void coordinates(point_t &p)
Definition: filling_curve.hh:485
void output_(std::ostream &ostr) const
Output a key using oct in 3d and poping values for 2 and 1D.
Definition: filling_curve.hh:150
Definition: filling_curve.hh:34
size_t depth() const
Definition: filling_curve.hh:86
int conflict_depth(filling_curve key_a, filling_curve key_b)
Search for the depth were two keys are in conflict.
Definition: filling_curve.hh:106
int_t value() const
Get the value associated to this key.
Definition: filling_curve.hh:167
static constexpr DERIVED root()
Definition: filling_curve.hh:74
void coordinates(point_t &p)
Definition: filling_curve.hh:288
virtual void coordinates(point_t &)
Convert this key to coordinates in range.
Definition: filling_curve.hh:171
void push(int_t bits)
Definition: filling_curve.hh:94
constexpr filling_curve parent() const
Return the parent of this key (depth - 1)
Definition: filling_curve.hh:137
Definition: control.hh:31