block_range.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2015 Virginia Tech
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Justus Calvin
19  * Department of Chemistry, Virginia Tech
20  *
21  * block_range.h
22  * May 29, 2015
23  *
24  */
25 
26 #ifndef TILEDARRAY_BLOCK_RANGE_H__INCLUDED
27 #define TILEDARRAY_BLOCK_RANGE_H__INCLUDED
28 
29 #include <TiledArray/range.h>
30 
31 namespace TiledArray {
32 
34 class BlockRange : public Range {
35  private:
36  using Range::datavec_;
37  using Range::offset_;
38  using Range::rank_;
39  using Range::volume_;
40 
41  Range::ordinal_type block_offset_ = 0ul;
42 
43  friend inline bool operator==(const BlockRange& r1, const BlockRange& r2);
44 
45  template <typename Index1, typename Index2,
46  typename = std::enable_if_t<detail::is_integral_range_v<Index1> &&
47  detail::is_integral_range_v<Index2>>>
48  void init(const Range& range, const Index1& lower_bound,
49  const Index2& upper_bound) {
50  TA_ASSERT(range.rank());
51 
52  // Initialize the block range data members
53  init_datavec(range.rank());
54  offset_ = range.offset();
55  volume_ = 1ul;
56  rank_ = range.rank();
57  block_offset_ = 0ul;
58 
59  // Construct temp pointers
60  const auto* MADNESS_RESTRICT const range_stride = range.stride_data();
61  auto* MADNESS_RESTRICT const lower = lobound_data_nc();
62  auto* MADNESS_RESTRICT const upper = upbound_data_nc();
63  auto* MADNESS_RESTRICT const extent = extent_data_nc();
64  auto* MADNESS_RESTRICT const stride = stride_data_nc();
65 
66  // initialize bounds and extents
67  auto lower_it = std::begin(lower_bound);
68  auto upper_it = std::begin(upper_bound);
69  auto lower_end = std::end(lower_bound);
70  auto upper_end = std::end(upper_bound);
71  for (int d = 0; lower_it != lower_end && upper_it != upper_end;
72  ++lower_it, ++upper_it, ++d) {
73  // Compute data for element i of lower, upper, and extent
74  const auto lower_bound_d = *lower_it;
75  const auto upper_bound_d = *upper_it;
76 
77  // Set the block range data
78  lower[d] = lower_bound_d;
79  upper[d] = upper_bound_d;
80  // Check input dimensions
81  TA_ASSERT(lower[d] >= range.lobound(d));
82  TA_ASSERT(lower[d] < upper[d]);
83  TA_ASSERT(upper[d] <= range.upbound(d));
84  extent[d] = upper[d] - lower[d];
85  TA_ASSERT(extent[d] ==
86  static_cast<index1_type>(upper_bound_d - lower_bound_d));
87  }
88 
89  // Compute strides, volume, and offset, starting with last (least
90  // significant) dimension
91  for (int d = int(rank_) - 1; d >= 0; --d) {
92  const auto range_stride_d = range_stride[d];
93  stride[d] = range_stride_d;
94  block_offset_ += lower[d] * range_stride_d;
95  volume_ *= extent[d];
96  }
97  }
98 
99  template <typename PairRange,
100  typename = std::enable_if_t<detail::is_gpair_range_v<PairRange>>>
101  void init(const Range& range, const PairRange& bounds) {
102  TA_ASSERT(range.rank());
103 
104  // Initialize the block range data members
105  init_datavec(range.rank());
106  offset_ = range.offset();
107  volume_ = 1ul;
108  rank_ = range.rank();
109  block_offset_ = 0ul;
110 
111  // Construct temp pointers
112  const auto* MADNESS_RESTRICT const range_stride = range.stride_data();
113  auto* MADNESS_RESTRICT const lower = lobound_data_nc();
114  auto* MADNESS_RESTRICT const upper = upbound_data_nc();
115  auto* MADNESS_RESTRICT const extent = extent_data_nc();
116  auto* MADNESS_RESTRICT const stride = stride_data_nc();
117 
118  // Compute range data
119  int d = 0;
120  for (auto&& bound_d : bounds) {
121  // Compute data for element i of lower, upper, and extent
122  const auto lower_bound_d = detail::at(bound_d, 0);
123  const auto upper_bound_d = detail::at(bound_d, 1);
124 
125  lower[d] = lower_bound_d;
126  upper[d] = upper_bound_d;
127  // Check input dimensions
128  TA_ASSERT(lower[d] >= range.lobound(d));
129  TA_ASSERT(lower[d] < upper[d]);
130  TA_ASSERT(upper[d] <= range.upbound(d));
131  extent[d] = upper[d] - lower[d];
132  TA_ASSERT(extent[d] ==
133  static_cast<index1_type>(upper_bound_d - lower_bound_d));
134  ++d;
135  }
136 
137  // Compute strides, volume, and offset, starting with last (least
138  // significant) dimension
139  for (int d = int(rank_) - 1; d >= 0; --d) {
140  const auto range_stride_d = range_stride[d];
141  stride[d] = range_stride_d;
142  block_offset_ += lower[d] * range_stride_d;
143  volume_ *= extent[d];
144  }
145  }
146 
147  public:
148  // Compiler generated functions
149  BlockRange() = default;
150  BlockRange(const BlockRange&) = default;
151  BlockRange(BlockRange&&) = default;
152  ~BlockRange() = default;
153  BlockRange& operator=(const BlockRange&) = default;
155 
156  // clang-format off
158 
177  // clang-format on
178  template <typename Index1, typename Index2,
179  typename = std::enable_if_t<detail::is_integral_range_v<Index1> &&
180  detail::is_integral_range_v<Index2>>>
181  BlockRange(const Range& range, const Index1& lower_bound,
182  const Index2& upper_bound)
183  : Range() {
184  init(range, lower_bound, upper_bound);
185  }
186 
187  // clang-format off
189 
204  // clang-format on
205  template <typename Index1, typename Index2,
206  typename = std::enable_if_t<std::is_integral_v<Index1> &&
207  std::is_integral_v<Index2>>>
208  BlockRange(const Range& range,
209  const std::initializer_list<Index1>& lower_bound,
210  const std::initializer_list<Index2>& upper_bound)
211  : Range() {
212  init(range, lower_bound, upper_bound);
213  }
214 
215  // clang-format off
217 
245  // clang-format on
246  template <typename PairRange,
247  typename = std::enable_if_t<detail::is_gpair_range_v<PairRange>>>
248  BlockRange(const Range& range, const PairRange& bounds) : Range() {
249  init(range, bounds);
250  }
251 
252  // clang-format off
254 
263  // clang-format on
264  template <typename GPair>
265  BlockRange(const Range& range, const std::initializer_list<GPair>& bounds,
266  std::enable_if_t<detail::is_gpair_v<GPair>>* = nullptr)
267  : Range() {
268 #ifndef NDEBUG
269  if constexpr (detail::is_contiguous_range_v<GPair>) {
270  for (auto&& bound_d : bounds) {
271  TA_ASSERT(size(bound_d) == 2);
272  }
273  }
274 #endif
275  init<std::initializer_list<GPair>>(range, bounds);
276  }
277 
278  // clang-format off
280 
289  // clang-format on
290  template <typename Index,
291  typename = std::enable_if_t<std::is_integral_v<Index>>>
292  BlockRange(const Range& range,
293  const std::initializer_list<std::initializer_list<Index>>& bounds)
294  : Range() {
295 #ifndef NDEBUG
296  for (auto&& bound_d : bounds) {
297  TA_ASSERT(size(bound_d) == 2);
298  }
299 #endif
300  init<std::initializer_list<std::initializer_list<Index>>>(range, bounds);
301  }
302 
304 
310  template <typename Index, typename std::enable_if_t<
311  detail::is_integral_range_v<Index>>* = nullptr>
312  ordinal_type ordinal(const Index& index) const {
313  return Range::ordinal(index);
314  }
315 
316  template <typename... Index,
317  typename std::enable_if<(sizeof...(Index) > 1ul)>::type* = nullptr>
318  ordinal_type ordinal(const Index&... index) const {
319  return Range::ordinal(index...);
320  }
321 
323 
329  // Check that index is contained by range.
331 
332  // Construct result coordinate index object and allocate its memory.
333  ordinal_type result = 0ul;
334 
335  // Get pointers to the data
336  const auto* MADNESS_RESTRICT const size = extent_data();
337  const auto* MADNESS_RESTRICT const stride = stride_data();
338 
339  // Compute the coordinate index of o in range.
340  for (int i = int(rank_) - 1; i >= 0; --i) {
341  const auto size_i = size[i];
342  const auto stride_i = stride[i];
343 
344  // Compute result index element i
345  result += (index % size_i) * stride_i;
346  index /= size_i;
347  }
348 
349  return result + block_offset_ - offset_;
350  }
351 
353  template <typename Index>
354  BlockRange& resize(const Index&, const Index&) {
355  // This function is here to shadow the base class resize function
356  TA_EXCEPTION("BlockRange::resize() is not supported");
357  return *this;
358  }
359 
361 
364  template <typename Index>
365  Range_& inplace_shift(const Index&) {
366  TA_EXCEPTION("BlockRange::inplace_shift() is not supported");
367  return *this;
368  }
369 
371 
374  template <typename Index>
375  Range_ shift(const Index&) {
376  TA_EXCEPTION("BlockRange::shift() is not supported");
377  return *this;
378  }
379 
380  void swap(BlockRange& other) {
381  Range::swap(other);
382  std::swap(block_offset_, other.block_offset_);
383  }
384 
386  template <typename Archive>
387  void serialize(const Archive& ar) const {
388  Range::serialize(ar);
389  ar& block_offset_;
390  }
391 }; // BlockRange
392 
393 // clang-format off
395 
399 // clang-format on
400 inline bool is_congruent(const BlockRange& r1, const BlockRange& r2) {
401  return is_congruent(static_cast<const Range&>(r1),
402  static_cast<const Range&>(r2));
403 }
404 
405 // clang-format off
407 
411 // clang-format on
412 inline bool is_congruent(const BlockRange& r1, const Range& r2) {
413  return is_congruent(static_cast<const Range&>(r1), r2);
414 }
415 
416 // clang-format off
418 
422 // clang-format on
423 inline bool is_congruent(const Range& r1, const BlockRange& r2) {
424  return is_congruent(r2, r1);
425 }
426 
428 
433 inline bool operator==(const BlockRange& r1, const BlockRange& r2) {
434  return r1.block_offset_ == r2.block_offset_ &&
435  static_cast<const Range&>(r1) == static_cast<const Range&>(r2);
436 }
437 
440 
443 inline bool is_contiguous(const BlockRange& range) { return true; }
444 
445 } // namespace TiledArray
446 
447 #endif // TILEDARRAY_BLOCK_RANGE_H__INCLUDED
index1_type * upbound_data_nc()
Definition: range.h:87
distance_type offset_
Ordinal index offset correction.
Definition: range.h:78
ordinal_type volume_
Total number of elements.
Definition: range.h:79
void serialize(const Archive &ar) const
Serialization Block range.
Definition: block_range.h:387
BlockRange(BlockRange &&)=default
void swap(Bitset< B > &b0, Bitset< B > &b1)
Definition: bitset.h:565
bool operator==(const BlockRange &r1, const BlockRange &r2)
BlockRange equality comparison.
Definition: block_range.h:433
ordinal_type ordinal(ordinal_type index) const
calculate the coordinate index of the ordinal index, index.
Definition: block_range.h:328
TA_1INDEX_TYPE index1_type
Definition: range.h:49
BlockRange & operator=(BlockRange &&)=default
#define TA_EXCEPTION(m)
Definition: error.h:83
Range that references a subblock of another range.
Definition: block_range.h:34
ordinal_type ordinal(const ordinal_type index) const
calculate the ordinal index of i
Definition: range.h:1008
index1_type * stride_data_nc()
Definition: range.h:89
#define TA_ASSERT(EXPR,...)
Definition: error.h:39
index_view_type lobound() const
Range lower bound accessor.
Definition: range.h:692
distance_type offset() const
Range offset.
Definition: range.h:795
index_view_type extent() const
Range extent accessor.
Definition: range.h:741
friend bool operator==(const BlockRange &r1, const BlockRange &r2)
BlockRange equality comparison.
Definition: block_range.h:433
bool includes(const Index &index) const
Check the coordinate to make sure it is within the range.
Definition: range.h:826
index1_type * extent_data_nc()
Definition: range.h:88
void serialize(Archive &ar)
Definition: range.h:1120
ordinal_type ordinal(const Index &index) const
calculate the ordinal index of i
Definition: block_range.h:312
void init_datavec(unsigned int rank)
Definition: range.h:82
BlockRange(const Range &range, const Index1 &lower_bound, const Index2 &upper_bound)
Construct a BlockRange defined by lower and upper bounds.
Definition: block_range.h:181
bool is_contiguous(const BlockRange &range)
Definition: block_range.h:443
BlockRange(const Range &range, const std::initializer_list< Index1 > &lower_bound, const std::initializer_list< Index2 > &upper_bound)
Construct a BlockRange defined by lower and upper bounds.
Definition: block_range.h:208
bool is_congruent(const BlockRange &r1, const BlockRange &r2)
Test that two BlockRange objects are congruent.
Definition: block_range.h:400
BlockRange(const Range &range, const PairRange &bounds)
Construct Range defined by a range of {lower,upper} bound pairs.
Definition: block_range.h:248
index_view_type stride() const
Range stride accessor.
Definition: range.h:766
container::svector< index1_type, 4 *TA_MAX_SOO_RANK_METADATA > datavec_
Definition: range.h:66
Range_ shift(const Index &)
Shift the lower and upper bound of this range.
Definition: block_range.h:375
const index1_type * stride_data() const
Range stride data accessor.
Definition: range.h:759
BlockRange & operator=(const BlockRange &)=default
BlockRange & resize(const Index &, const Index &)
Resize of block range is not supported.
Definition: block_range.h:354
BlockRange(const BlockRange &)=default
BlockRange(const Range &range, const std::initializer_list< GPair > &bounds, std::enable_if_t< detail::is_gpair_v< GPair >> *=nullptr)
Construct range defined by an initializer_list of std::initializer_list{lower,upper} bounds.
Definition: block_range.h:265
ordinal_type ordinal(const Index &... index) const
Definition: block_range.h:318
BlockRange(const Range &range, const std::initializer_list< std::initializer_list< Index >> &bounds)
Construct range defined by an initializer_list of std::initializer_list{lower,upper} bounds.
Definition: block_range.h:292
void swap(BlockRange &other)
Definition: block_range.h:380
unsigned int rank_
The rank (or number of dimensions) in the range.
Definition: range.h:80
decltype(auto) at(GeneralizedPair &&v, std::size_t idx)
at(pair, i) extracts i-th element from gpair
Definition: type_traits.h:1268
void swap(Range_ &other)
Definition: range.h:1124
index_view_type upbound() const
Range upper bound accessor.
Definition: range.h:717
std::size_t ordinal_type
Ordinal type, to conform to TWG spec.
Definition: range.h:59
const index1_type * extent_data() const
Range extent data accessor.
Definition: range.h:735
index_type index
Coordinate index type (deprecated)
Definition: range.h:54
Range_ & inplace_shift(const Index &)
Shift the lower and upper bound of this range.
Definition: block_range.h:365
unsigned int rank() const
Rank accessor.
Definition: range.h:669
index1_type * lobound_data_nc()
Definition: range.h:86
A (hyperrectangular) interval on , space of integer -indices.
Definition: range.h:46